summaryrefslogtreecommitdiff
path: root/libgo/go
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2011-12-12 23:40:51 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2011-12-12 23:40:51 +0000
commit46bc1fe2f5a3c7ee4273b99d700fecf1555f64e0 (patch)
tree0c68629fac9d7c6f103b401c9063ef00ed259f06 /libgo/go
parentdc15d51eb56c0efe84bf82b02ac2ba9a231ce69b (diff)
downloadgcc-46bc1fe2f5a3c7ee4273b99d700fecf1555f64e0.tar.gz
libgo: Update to weekly.2011-11-18.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@182266 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo/go')
-rw-r--r--libgo/go/bufio/bufio_test.go7
-rw-r--r--libgo/go/builtin/builtin.go12
-rw-r--r--libgo/go/bytes/bytes_test.go63
-rw-r--r--libgo/go/compress/lzw/reader.go5
-rw-r--r--libgo/go/compress/lzw/writer.go17
-rw-r--r--libgo/go/compress/lzw/writer_test.go4
-rw-r--r--libgo/go/compress/zlib/writer_test.go4
-rw-r--r--libgo/go/crypto/aes/cipher.go2
-rw-r--r--libgo/go/crypto/blowfish/cipher.go2
-rw-r--r--libgo/go/crypto/rand/rand_windows.go12
-rw-r--r--libgo/go/crypto/rand/util.go4
-rw-r--r--libgo/go/crypto/tls/conn.go5
-rw-r--r--libgo/go/crypto/tls/handshake_messages.go161
-rw-r--r--libgo/go/crypto/tls/handshake_messages_test.go4
-rw-r--r--libgo/go/crypto/tls/root_windows.go4
-rw-r--r--libgo/go/crypto/xtea/cipher.go2
-rw-r--r--libgo/go/encoding/json/bench_test.go157
-rw-r--r--libgo/go/encoding/json/decode.go6
-rw-r--r--libgo/go/encoding/json/scanner.go19
-rw-r--r--libgo/go/encoding/json/scanner_test.go5
-rw-r--r--libgo/go/encoding/xml/xml_test.go17
-rw-r--r--libgo/go/exp/inotify/inotify_linux.go22
-rw-r--r--libgo/go/exp/sql/convert.go15
-rw-r--r--libgo/go/exp/sql/driver/driver.go22
-rw-r--r--libgo/go/exp/sql/fakedb_test.go33
-rw-r--r--libgo/go/exp/sql/sql.go78
-rw-r--r--libgo/go/exp/sql/sql_test.go11
-rw-r--r--libgo/go/exp/ssh/cipher.go88
-rw-r--r--libgo/go/exp/ssh/cipher_test.go62
-rw-r--r--libgo/go/exp/ssh/client.go17
-rw-r--r--libgo/go/exp/ssh/client_auth.go148
-rw-r--r--libgo/go/exp/ssh/client_auth_test.go248
-rw-r--r--libgo/go/exp/ssh/client_func_test.go61
-rw-r--r--libgo/go/exp/ssh/common.go101
-rw-r--r--libgo/go/exp/ssh/messages.go8
-rw-r--r--libgo/go/exp/ssh/server.go54
-rw-r--r--libgo/go/exp/ssh/tcpip.go146
-rw-r--r--libgo/go/exp/ssh/transport.go51
-rw-r--r--libgo/go/exp/terminal/shell.go356
-rw-r--r--libgo/go/exp/terminal/terminal.go401
-rw-r--r--libgo/go/exp/terminal/terminal_test.go (renamed from libgo/go/exp/terminal/shell_test.go)4
-rw-r--r--libgo/go/exp/terminal/util.go102
-rw-r--r--libgo/go/fmt/fmt_test.go4
-rw-r--r--libgo/go/fmt/print.go8
-rw-r--r--libgo/go/fmt/scan_test.go8
-rw-r--r--libgo/go/go/ast/ast.go100
-rw-r--r--libgo/go/go/ast/filter.go70
-rw-r--r--libgo/go/go/build/build_test.go16
-rw-r--r--libgo/go/go/printer/printer.go36
-rw-r--r--libgo/go/html/doc.go4
-rw-r--r--libgo/go/html/parse.go590
-rw-r--r--libgo/go/html/parse_test.go8
-rw-r--r--libgo/go/html/render.go25
-rw-r--r--libgo/go/html/template/content.go21
-rw-r--r--libgo/go/html/template/escape_test.go35
-rw-r--r--libgo/go/html/template/js.go20
-rw-r--r--libgo/go/html/token.go26
-rw-r--r--libgo/go/image/tiff/buffer.go7
-rw-r--r--libgo/go/io/ioutil/tempfile.go4
-rw-r--r--libgo/go/log/syslog/syslog.go3
-rw-r--r--libgo/go/math/big/int.go32
-rw-r--r--libgo/go/math/big/nat.go10
-rw-r--r--libgo/go/math/big/nat_test.go26
-rw-r--r--libgo/go/math/big/rat.go14
-rw-r--r--libgo/go/math/gamma.go12
-rw-r--r--libgo/go/math/lgamma.go155
-rw-r--r--libgo/go/mime/multipart/formdata.go2
-rw-r--r--libgo/go/mime/type.go45
-rw-r--r--libgo/go/mime/type_test.go8
-rw-r--r--libgo/go/mime/type_unix.go59
-rw-r--r--libgo/go/mime/type_windows.go61
-rw-r--r--libgo/go/net/cgo_unix.go2
-rw-r--r--libgo/go/net/fd.go204
-rw-r--r--libgo/go/net/fd_linux.go16
-rw-r--r--libgo/go/net/fd_openbsd.go11
-rw-r--r--libgo/go/net/fd_windows.go76
-rw-r--r--libgo/go/net/file.go4
-rw-r--r--libgo/go/net/hosts.go6
-rw-r--r--libgo/go/net/http/cgi/host_test.go15
-rw-r--r--libgo/go/net/http/chunked.go125
-rw-r--r--libgo/go/net/http/chunked_test.go39
-rw-r--r--libgo/go/net/http/client_test.go27
-rw-r--r--libgo/go/net/http/fcgi/child.go143
-rw-r--r--libgo/go/net/http/fcgi/fcgi.go41
-rw-r--r--libgo/go/net/http/fcgi/fcgi_test.go47
-rw-r--r--libgo/go/net/http/fs.go8
-rw-r--r--libgo/go/net/http/fs_test.go28
-rw-r--r--libgo/go/net/http/httputil/chunked.go140
-rw-r--r--libgo/go/net/http/httputil/chunked_test.go8
-rw-r--r--libgo/go/net/http/httputil/persist.go10
-rw-r--r--libgo/go/net/http/readrequest_test.go6
-rw-r--r--libgo/go/net/http/request.go90
-rw-r--r--libgo/go/net/http/response_test.go4
-rw-r--r--libgo/go/net/http/serve_test.go27
-rw-r--r--libgo/go/net/http/server.go10
-rw-r--r--libgo/go/net/http/sniff_test.go33
-rw-r--r--libgo/go/net/http/transfer.go4
-rw-r--r--libgo/go/net/http/transport.go2
-rw-r--r--libgo/go/net/http/transport_windows.go6
-rw-r--r--libgo/go/net/interface_bsd.go16
-rw-r--r--libgo/go/net/interface_darwin.go8
-rw-r--r--libgo/go/net/interface_freebsd.go8
-rw-r--r--libgo/go/net/interface_linux.go32
-rw-r--r--libgo/go/net/interface_windows.go4
-rw-r--r--libgo/go/net/ipsock.go4
-rw-r--r--libgo/go/net/ipsock_posix.go8
-rw-r--r--libgo/go/net/lookup_windows.go16
-rw-r--r--libgo/go/net/newpollserver.go7
-rw-r--r--libgo/go/net/pipe.go4
-rw-r--r--libgo/go/net/sendfile_linux.go6
-rw-r--r--libgo/go/net/sendfile_windows.go2
-rw-r--r--libgo/go/net/sock.go8
-rw-r--r--libgo/go/net/tcpsock_posix.go4
-rw-r--r--libgo/go/net/unixsock_posix.go4
-rw-r--r--libgo/go/os/dir_largefile.go2
-rw-r--r--libgo/go/os/dir_regfile.go2
-rw-r--r--libgo/go/os/dir_unix.go4
-rw-r--r--libgo/go/os/env.go49
-rw-r--r--libgo/go/os/env_plan9.go99
-rw-r--r--libgo/go/os/env_unix.go112
-rw-r--r--libgo/go/os/env_windows.go128
-rw-r--r--libgo/go/os/error_plan9.go8
-rw-r--r--libgo/go/os/error_posix.go106
-rw-r--r--libgo/go/os/exec/exec.go8
-rw-r--r--libgo/go/os/exec_plan9.go10
-rw-r--r--libgo/go/os/exec_posix.go8
-rw-r--r--libgo/go/os/exec_unix.go6
-rw-r--r--libgo/go/os/exec_windows.go23
-rw-r--r--libgo/go/os/file.go38
-rw-r--r--libgo/go/os/file_plan9.go61
-rw-r--r--libgo/go/os/file_posix.go54
-rw-r--r--libgo/go/os/file_unix.go65
-rw-r--r--libgo/go/os/os_test.go7
-rw-r--r--libgo/go/os/proc.go4
-rw-r--r--libgo/go/os/stat_plan9.go6
-rw-r--r--libgo/go/os/sys_bsd.go7
-rw-r--r--libgo/go/os/time.go2
-rw-r--r--libgo/go/os/user/lookup_unix.go5
-rw-r--r--libgo/go/reflect/all_test.go55
-rw-r--r--libgo/go/reflect/deepequal.go6
-rw-r--r--libgo/go/reflect/type.go36
-rw-r--r--libgo/go/reflect/value.go1396
-rw-r--r--libgo/go/regexp/regexp.go2
-rw-r--r--libgo/go/strconv/decimal.go27
-rw-r--r--libgo/go/strconv/decimal_test.go12
-rw-r--r--libgo/go/strconv/ftoa.go9
-rw-r--r--libgo/go/strconv/ftoa_test.go24
-rw-r--r--libgo/go/strconv/internal_test.go6
-rw-r--r--libgo/go/strings/strings_test.go63
-rw-r--r--libgo/go/sync/mutex.go2
-rw-r--r--libgo/go/syscall/bpf_bsd.go160
-rw-r--r--libgo/go/syscall/env_plan9.go74
-rw-r--r--libgo/go/syscall/env_unix.go85
-rw-r--r--libgo/go/syscall/env_windows.go77
-rw-r--r--libgo/go/syscall/errno.c13
-rw-r--r--libgo/go/syscall/errstr.go4
-rw-r--r--libgo/go/syscall/exec_stubs.go4
-rw-r--r--libgo/go/syscall/exec_unix.go121
-rw-r--r--libgo/go/syscall/exec_windows.go48
-rw-r--r--libgo/go/syscall/libcall_irix.go2
-rw-r--r--libgo/go/syscall/libcall_linux.go172
-rw-r--r--libgo/go/syscall/libcall_posix.go160
-rw-r--r--libgo/go/syscall/libcall_posix_largefile.go20
-rw-r--r--libgo/go/syscall/libcall_posix_regfile.go20
-rw-r--r--libgo/go/syscall/libcall_solaris_386.go4
-rw-r--r--libgo/go/syscall/libcall_solaris_amd64.go2
-rw-r--r--libgo/go/syscall/libcall_solaris_sparc.go2
-rw-r--r--libgo/go/syscall/libcall_solaris_sparc64.go2
-rw-r--r--libgo/go/syscall/libcall_support.go4
-rw-r--r--libgo/go/syscall/libcall_uname.go2
-rw-r--r--libgo/go/syscall/libcall_wait4.go5
-rw-r--r--libgo/go/syscall/libcall_waitpid.go5
-rw-r--r--libgo/go/syscall/lsf_linux.go28
-rw-r--r--libgo/go/syscall/mksyscall.awk6
-rw-r--r--libgo/go/syscall/netlink_linux.go43
-rw-r--r--libgo/go/syscall/route_bsd.go35
-rw-r--r--libgo/go/syscall/route_darwin.go2
-rw-r--r--libgo/go/syscall/route_freebsd.go2
-rw-r--r--libgo/go/syscall/sleep_rtems.go4
-rw-r--r--libgo/go/syscall/sleep_select.go4
-rw-r--r--libgo/go/syscall/sockcmsg_linux.go4
-rw-r--r--libgo/go/syscall/sockcmsg_unix.go14
-rw-r--r--libgo/go/syscall/socket.go182
-rw-r--r--libgo/go/syscall/socket_bsd.go10
-rw-r--r--libgo/go/syscall/socket_irix.go10
-rw-r--r--libgo/go/syscall/socket_linux.go26
-rw-r--r--libgo/go/syscall/socket_solaris.go10
-rw-r--r--libgo/go/syscall/syscall.go5
-rw-r--r--libgo/go/syscall/syscall_unix.go66
-rw-r--r--libgo/go/testing/benchmark.go8
-rw-r--r--libgo/go/testing/example.go28
-rw-r--r--libgo/go/testing/testing.go55
-rw-r--r--libgo/go/text/tabwriter/tabwriter.go3
-rw-r--r--libgo/go/text/template/exec_test.go6
-rw-r--r--libgo/go/text/template/parse.go14
-rw-r--r--libgo/go/text/template/parse/parse.go75
-rw-r--r--libgo/go/text/template/parse/parse_test.go2
-rw-r--r--libgo/go/text/template/parse/set.go38
-rw-r--r--libgo/go/text/template/set.go1
-rw-r--r--libgo/go/time/sleep.go194
-rw-r--r--libgo/go/time/sleep_test.go19
-rw-r--r--libgo/go/time/sys.go23
-rw-r--r--libgo/go/time/sys_plan9.go13
-rw-r--r--libgo/go/time/sys_unix.go8
-rw-r--r--libgo/go/time/sys_windows.go13
-rw-r--r--libgo/go/time/tick.go182
-rw-r--r--libgo/go/time/time.go60
-rw-r--r--libgo/go/time/time_test.go62
-rw-r--r--libgo/go/time/zoneinfo_unix.go12
-rw-r--r--libgo/go/time/zoneinfo_windows.go2
-rw-r--r--libgo/go/websocket/websocket.go10
211 files changed, 6000 insertions, 3929 deletions
diff --git a/libgo/go/bufio/bufio_test.go b/libgo/go/bufio/bufio_test.go
index 1f893951c15..54029cd40fd 100644
--- a/libgo/go/bufio/bufio_test.go
+++ b/libgo/go/bufio/bufio_test.go
@@ -10,7 +10,6 @@ import (
"fmt"
"io"
"io/ioutil"
- "os"
"strings"
"testing"
"testing/iotest"
@@ -425,9 +424,9 @@ var errorWriterTests = []errorWriterTest{
{0, 1, nil, io.ErrShortWrite},
{1, 2, nil, io.ErrShortWrite},
{1, 1, nil, nil},
- {0, 1, os.EPIPE, os.EPIPE},
- {1, 2, os.EPIPE, os.EPIPE},
- {1, 1, os.EPIPE, os.EPIPE},
+ {0, 1, io.ErrClosedPipe, io.ErrClosedPipe},
+ {1, 2, io.ErrClosedPipe, io.ErrClosedPipe},
+ {1, 1, io.ErrClosedPipe, io.ErrClosedPipe},
}
func TestWriteErrors(t *testing.T) {
diff --git a/libgo/go/builtin/builtin.go b/libgo/go/builtin/builtin.go
index 5a7aaf364db..e81616ca418 100644
--- a/libgo/go/builtin/builtin.go
+++ b/libgo/go/builtin/builtin.go
@@ -91,6 +91,11 @@ type rune rune
// invocation.
type Type int
+// Type1 is here for the purposes of documentation only. It is a stand-in
+// for any Go type, but represents the same type for any given function
+// invocation.
+type Type1 int
+
// IntegerType is here for the purposes of documentation only. It is a stand-in
// for any integer type: int, uint, int8 etc.
type IntegerType int
@@ -119,6 +124,11 @@ func append(slice []Type, elems ...Type) []Type
// len(src) and len(dst).
func copy(dst, src []Type) int
+// The delete built-in function deletes the element with the specified key
+// (m[key]) from the map. If there is no such element, delete is a no-op.
+// If m is nil, delete panics.
+func delete(m map[Type]Type1, key Type)
+
// The len built-in function returns the length of v, according to its type:
// Array: the number of elements in v.
// Pointer to array: the number of elements in *v (even if v is nil).
@@ -171,7 +181,7 @@ func complex(r, i FloatType) ComplexType
// The return value will be floating point type corresponding to the type of c.
func real(c ComplexType) FloatType
-// The imaginary built-in function returns the imaginary part of the complex
+// The imag built-in function returns the imaginary part of the complex
// number c. The return value will be floating point type corresponding to
// the type of c.
func imag(c ComplexType) FloatType
diff --git a/libgo/go/bytes/bytes_test.go b/libgo/go/bytes/bytes_test.go
index 9256b184274..21a1a4f5808 100644
--- a/libgo/go/bytes/bytes_test.go
+++ b/libgo/go/bytes/bytes_test.go
@@ -662,48 +662,49 @@ func TestRunes(t *testing.T) {
}
type TrimTest struct {
- f func([]byte, string) []byte
+ f string
in, cutset, out string
}
var trimTests = []TrimTest{
- {Trim, "abba", "a", "bb"},
- {Trim, "abba", "ab", ""},
- {TrimLeft, "abba", "ab", ""},
- {TrimRight, "abba", "ab", ""},
- {TrimLeft, "abba", "a", "bba"},
- {TrimRight, "abba", "a", "abb"},
- {Trim, "<tag>", "<>", "tag"},
- {Trim, "* listitem", " *", "listitem"},
- {Trim, `"quote"`, `"`, "quote"},
- {Trim, "\u2C6F\u2C6F\u0250\u0250\u2C6F\u2C6F", "\u2C6F", "\u0250\u0250"},
+ {"Trim", "abba", "a", "bb"},
+ {"Trim", "abba", "ab", ""},
+ {"TrimLeft", "abba", "ab", ""},
+ {"TrimRight", "abba", "ab", ""},
+ {"TrimLeft", "abba", "a", "bba"},
+ {"TrimRight", "abba", "a", "abb"},
+ {"Trim", "<tag>", "<>", "tag"},
+ {"Trim", "* listitem", " *", "listitem"},
+ {"Trim", `"quote"`, `"`, "quote"},
+ {"Trim", "\u2C6F\u2C6F\u0250\u0250\u2C6F\u2C6F", "\u2C6F", "\u0250\u0250"},
//empty string tests
- {Trim, "abba", "", "abba"},
- {Trim, "", "123", ""},
- {Trim, "", "", ""},
- {TrimLeft, "abba", "", "abba"},
- {TrimLeft, "", "123", ""},
- {TrimLeft, "", "", ""},
- {TrimRight, "abba", "", "abba"},
- {TrimRight, "", "123", ""},
- {TrimRight, "", "", ""},
- {TrimRight, "☺\xc0", "☺", "☺\xc0"},
+ {"Trim", "abba", "", "abba"},
+ {"Trim", "", "123", ""},
+ {"Trim", "", "", ""},
+ {"TrimLeft", "abba", "", "abba"},
+ {"TrimLeft", "", "123", ""},
+ {"TrimLeft", "", "", ""},
+ {"TrimRight", "abba", "", "abba"},
+ {"TrimRight", "", "123", ""},
+ {"TrimRight", "", "", ""},
+ {"TrimRight", "☺\xc0", "☺", "☺\xc0"},
}
func TestTrim(t *testing.T) {
for _, tc := range trimTests {
- actual := string(tc.f([]byte(tc.in), tc.cutset))
- var name string
- switch tc.f {
- case Trim:
- name = "Trim"
- case TrimLeft:
- name = "TrimLeft"
- case TrimRight:
- name = "TrimRight"
+ name := tc.f
+ var f func([]byte, string) []byte
+ switch name {
+ case "Trim":
+ f = Trim
+ case "TrimLeft":
+ f = TrimLeft
+ case "TrimRight":
+ f = TrimRight
default:
- t.Error("Undefined trim function")
+ t.Error("Undefined trim function %s", name)
}
+ actual := string(f([]byte(tc.in), tc.cutset))
if actual != tc.out {
t.Errorf("%s(%q, %q) = %q; want %q", name, tc.in, tc.cutset, actual, tc.out)
}
diff --git a/libgo/go/compress/lzw/reader.go b/libgo/go/compress/lzw/reader.go
index c787a9568b3..0ed742c8977 100644
--- a/libgo/go/compress/lzw/reader.go
+++ b/libgo/go/compress/lzw/reader.go
@@ -19,7 +19,6 @@ import (
"errors"
"fmt"
"io"
- "os"
)
// Order specifies the bit ordering in an LZW data stream.
@@ -212,8 +211,10 @@ func (d *decoder) flush() {
d.o = 0
}
+var errClosed = errors.New("compress/lzw: reader/writer is closed")
+
func (d *decoder) Close() error {
- d.err = os.EINVAL // in case any Reads come along
+ d.err = errClosed // in case any Reads come along
return nil
}
diff --git a/libgo/go/compress/lzw/writer.go b/libgo/go/compress/lzw/writer.go
index 3f380fadce2..488ba6428db 100644
--- a/libgo/go/compress/lzw/writer.go
+++ b/libgo/go/compress/lzw/writer.go
@@ -9,7 +9,6 @@ import (
"errors"
"fmt"
"io"
- "os"
)
// A writer is a buffered, flushable writer.
@@ -49,8 +48,9 @@ const (
type encoder struct {
// w is the writer that compressed bytes are written to.
w writer
- // write, bits, nBits and width are the state for converting a code stream
- // into a byte stream.
+ // order, write, bits, nBits and width are the state for
+ // converting a code stream into a byte stream.
+ order Order
write func(*encoder, uint32) error
bits uint32
nBits uint
@@ -64,7 +64,7 @@ type encoder struct {
// call. It is equal to invalidCode if there was no such call.
savedCode uint32
// err is the first error encountered during writing. Closing the encoder
- // will make any future Write calls return os.EINVAL.
+ // will make any future Write calls return errClosed
err error
// table is the hash table from 20-bit keys to 12-bit values. Each table
// entry contains key<<12|val and collisions resolve by linear probing.
@@ -191,13 +191,13 @@ loop:
// flush e's underlying writer.
func (e *encoder) Close() error {
if e.err != nil {
- if e.err == os.EINVAL {
+ if e.err == errClosed {
return nil
}
return e.err
}
- // Make any future calls to Write return os.EINVAL.
- e.err = os.EINVAL
+ // Make any future calls to Write return errClosed.
+ e.err = errClosed
// Write the savedCode if valid.
if e.savedCode != invalidCode {
if err := e.write(e, e.savedCode); err != nil {
@@ -214,7 +214,7 @@ func (e *encoder) Close() error {
}
// Write the final bits.
if e.nBits > 0 {
- if e.write == (*encoder).writeMSB {
+ if e.order == MSB {
e.bits >>= 24
}
if err := e.w.WriteByte(uint8(e.bits)); err != nil {
@@ -250,6 +250,7 @@ func NewWriter(w io.Writer, order Order, litWidth int) io.WriteCloser {
lw := uint(litWidth)
return &encoder{
w: bw,
+ order: order,
write: write,
width: 1 + lw,
litWidth: lw,
diff --git a/libgo/go/compress/lzw/writer_test.go b/libgo/go/compress/lzw/writer_test.go
index 154cdf8090e..d249a09b295 100644
--- a/libgo/go/compress/lzw/writer_test.go
+++ b/libgo/go/compress/lzw/writer_test.go
@@ -50,10 +50,6 @@ func testFile(t *testing.T, fn string, order Order, litWidth int) {
return
}
_, err1 := lzww.Write(b[:n])
- if err1 == os.EPIPE {
- // Fail, but do not report the error, as some other (presumably reportable) error broke the pipe.
- return
- }
if err1 != nil {
t.Errorf("%s (order=%d litWidth=%d): %v", fn, order, litWidth, err1)
return
diff --git a/libgo/go/compress/zlib/writer_test.go b/libgo/go/compress/zlib/writer_test.go
index 32f05ab6856..a71894da320 100644
--- a/libgo/go/compress/zlib/writer_test.go
+++ b/libgo/go/compress/zlib/writer_test.go
@@ -59,10 +59,6 @@ func testLevelDict(t *testing.T, fn string, b0 []byte, level int, d string) {
}
defer zlibw.Close()
_, err = zlibw.Write(b0)
- if err == os.EPIPE {
- // Fail, but do not report the error, as some other (presumably reported) error broke the pipe.
- return
- }
if err != nil {
t.Errorf("%s (level=%d, dict=%q): %v", fn, level, d, err)
return
diff --git a/libgo/go/crypto/aes/cipher.go b/libgo/go/crypto/aes/cipher.go
index 5ad75eccb50..28752e73613 100644
--- a/libgo/go/crypto/aes/cipher.go
+++ b/libgo/go/crypto/aes/cipher.go
@@ -41,7 +41,7 @@ func NewCipher(key []byte) (*Cipher, error) {
}
// BlockSize returns the AES block size, 16 bytes.
-// It is necessary to satisfy the Cipher interface in the
+// It is necessary to satisfy the Block interface in the
// package "crypto/cipher".
func (c *Cipher) BlockSize() int { return BlockSize }
diff --git a/libgo/go/crypto/blowfish/cipher.go b/libgo/go/crypto/blowfish/cipher.go
index a5d56d2ebae..94e10f0e267 100644
--- a/libgo/go/crypto/blowfish/cipher.go
+++ b/libgo/go/crypto/blowfish/cipher.go
@@ -54,7 +54,7 @@ func NewSaltedCipher(key, salt []byte) (*Cipher, error) {
}
// BlockSize returns the Blowfish block size, 8 bytes.
-// It is necessary to satisfy the Cipher interface in the
+// It is necessary to satisfy the Block interface in the
// package "crypto/cipher".
func (c *Cipher) BlockSize() int { return BlockSize }
diff --git a/libgo/go/crypto/rand/rand_windows.go b/libgo/go/crypto/rand/rand_windows.go
index 590571d23f6..2b2bd4bba6b 100644
--- a/libgo/go/crypto/rand/rand_windows.go
+++ b/libgo/go/crypto/rand/rand_windows.go
@@ -28,16 +28,16 @@ func (r *rngReader) Read(b []byte) (n int, err error) {
if r.prov == 0 {
const provType = syscall.PROV_RSA_FULL
const flags = syscall.CRYPT_VERIFYCONTEXT | syscall.CRYPT_SILENT
- errno := syscall.CryptAcquireContext(&r.prov, nil, nil, provType, flags)
- if errno != 0 {
+ err := syscall.CryptAcquireContext(&r.prov, nil, nil, provType, flags)
+ if err != nil {
r.mu.Unlock()
- return 0, os.NewSyscallError("CryptAcquireContext", errno)
+ return 0, os.NewSyscallError("CryptAcquireContext", err)
}
}
r.mu.Unlock()
- errno := syscall.CryptGenRandom(r.prov, uint32(len(b)), &b[0])
- if errno != 0 {
- return 0, os.NewSyscallError("CryptGenRandom", errno)
+ err = syscall.CryptGenRandom(r.prov, uint32(len(b)), &b[0])
+ if err != nil {
+ return 0, os.NewSyscallError("CryptGenRandom", err)
}
return len(b), nil
}
diff --git a/libgo/go/crypto/rand/util.go b/libgo/go/crypto/rand/util.go
index b44ae9897ba..fc5fe6c65e9 100644
--- a/libgo/go/crypto/rand/util.go
+++ b/libgo/go/crypto/rand/util.go
@@ -5,16 +5,16 @@
package rand
import (
+ "errors"
"io"
"math/big"
- "os"
)
// Prime returns a number, p, of the given size, such that p is prime
// with high probability.
func Prime(rand io.Reader, bits int) (p *big.Int, err error) {
if bits < 1 {
- err = os.EINVAL
+ err = errors.New("crypto/rand: prime size must be positive")
}
b := uint(bits % 8)
diff --git a/libgo/go/crypto/tls/conn.go b/libgo/go/crypto/tls/conn.go
index f4178e30c58..b8fa2737f67 100644
--- a/libgo/go/crypto/tls/conn.go
+++ b/libgo/go/crypto/tls/conn.go
@@ -93,7 +93,8 @@ func (c *Conn) SetTimeout(nsec int64) error {
}
// SetReadTimeout sets the time (in nanoseconds) that
-// Read will wait for data before returning os.EAGAIN.
+// Read will wait for data before returning a net.Error
+// with Timeout() == true.
// Setting nsec == 0 (the default) disables the deadline.
func (c *Conn) SetReadTimeout(nsec int64) error {
return c.conn.SetReadTimeout(nsec)
@@ -737,7 +738,7 @@ func (c *Conn) Write(b []byte) (n int, err error) {
return c.writeRecord(recordTypeApplicationData, b)
}
-// Read can be made to time out and return err == os.EAGAIN
+// Read can be made to time out and return a net.Error with Timeout() == true
// after a fixed time limit; see SetTimeout and SetReadTimeout.
func (c *Conn) Read(b []byte) (n int, err error) {
if err = c.Handshake(); err != nil {
diff --git a/libgo/go/crypto/tls/handshake_messages.go b/libgo/go/crypto/tls/handshake_messages.go
index f11232d8ee5..5438e749ce8 100644
--- a/libgo/go/crypto/tls/handshake_messages.go
+++ b/libgo/go/crypto/tls/handshake_messages.go
@@ -4,6 +4,8 @@
package tls
+import "bytes"
+
type clientHelloMsg struct {
raw []byte
vers uint16
@@ -18,6 +20,25 @@ type clientHelloMsg struct {
supportedPoints []uint8
}
+func (m *clientHelloMsg) equal(i interface{}) bool {
+ m1, ok := i.(*clientHelloMsg)
+ if !ok {
+ return false
+ }
+
+ return bytes.Equal(m.raw, m1.raw) &&
+ m.vers == m1.vers &&
+ bytes.Equal(m.random, m1.random) &&
+ bytes.Equal(m.sessionId, m1.sessionId) &&
+ eqUint16s(m.cipherSuites, m1.cipherSuites) &&
+ bytes.Equal(m.compressionMethods, m1.compressionMethods) &&
+ m.nextProtoNeg == m1.nextProtoNeg &&
+ m.serverName == m1.serverName &&
+ m.ocspStapling == m1.ocspStapling &&
+ eqUint16s(m.supportedCurves, m1.supportedCurves) &&
+ bytes.Equal(m.supportedPoints, m1.supportedPoints)
+}
+
func (m *clientHelloMsg) marshal() []byte {
if m.raw != nil {
return m.raw
@@ -309,6 +330,23 @@ type serverHelloMsg struct {
ocspStapling bool
}
+func (m *serverHelloMsg) equal(i interface{}) bool {
+ m1, ok := i.(*serverHelloMsg)
+ if !ok {
+ return false
+ }
+
+ return bytes.Equal(m.raw, m1.raw) &&
+ m.vers == m1.vers &&
+ bytes.Equal(m.random, m1.random) &&
+ bytes.Equal(m.sessionId, m1.sessionId) &&
+ m.cipherSuite == m1.cipherSuite &&
+ m.compressionMethod == m1.compressionMethod &&
+ m.nextProtoNeg == m1.nextProtoNeg &&
+ eqStrings(m.nextProtos, m1.nextProtos) &&
+ m.ocspStapling == m1.ocspStapling
+}
+
func (m *serverHelloMsg) marshal() []byte {
if m.raw != nil {
return m.raw
@@ -463,6 +501,16 @@ type certificateMsg struct {
certificates [][]byte
}
+func (m *certificateMsg) equal(i interface{}) bool {
+ m1, ok := i.(*certificateMsg)
+ if !ok {
+ return false
+ }
+
+ return bytes.Equal(m.raw, m1.raw) &&
+ eqByteSlices(m.certificates, m1.certificates)
+}
+
func (m *certificateMsg) marshal() (x []byte) {
if m.raw != nil {
return m.raw
@@ -540,6 +588,16 @@ type serverKeyExchangeMsg struct {
key []byte
}
+func (m *serverKeyExchangeMsg) equal(i interface{}) bool {
+ m1, ok := i.(*serverKeyExchangeMsg)
+ if !ok {
+ return false
+ }
+
+ return bytes.Equal(m.raw, m1.raw) &&
+ bytes.Equal(m.key, m1.key)
+}
+
func (m *serverKeyExchangeMsg) marshal() []byte {
if m.raw != nil {
return m.raw
@@ -571,6 +629,17 @@ type certificateStatusMsg struct {
response []byte
}
+func (m *certificateStatusMsg) equal(i interface{}) bool {
+ m1, ok := i.(*certificateStatusMsg)
+ if !ok {
+ return false
+ }
+
+ return bytes.Equal(m.raw, m1.raw) &&
+ m.statusType == m1.statusType &&
+ bytes.Equal(m.response, m1.response)
+}
+
func (m *certificateStatusMsg) marshal() []byte {
if m.raw != nil {
return m.raw
@@ -622,6 +691,11 @@ func (m *certificateStatusMsg) unmarshal(data []byte) bool {
type serverHelloDoneMsg struct{}
+func (m *serverHelloDoneMsg) equal(i interface{}) bool {
+ _, ok := i.(*serverHelloDoneMsg)
+ return ok
+}
+
func (m *serverHelloDoneMsg) marshal() []byte {
x := make([]byte, 4)
x[0] = typeServerHelloDone
@@ -637,6 +711,16 @@ type clientKeyExchangeMsg struct {
ciphertext []byte
}
+func (m *clientKeyExchangeMsg) equal(i interface{}) bool {
+ m1, ok := i.(*clientKeyExchangeMsg)
+ if !ok {
+ return false
+ }
+
+ return bytes.Equal(m.raw, m1.raw) &&
+ bytes.Equal(m.ciphertext, m1.ciphertext)
+}
+
func (m *clientKeyExchangeMsg) marshal() []byte {
if m.raw != nil {
return m.raw
@@ -671,6 +755,16 @@ type finishedMsg struct {
verifyData []byte
}
+func (m *finishedMsg) equal(i interface{}) bool {
+ m1, ok := i.(*finishedMsg)
+ if !ok {
+ return false
+ }
+
+ return bytes.Equal(m.raw, m1.raw) &&
+ bytes.Equal(m.verifyData, m1.verifyData)
+}
+
func (m *finishedMsg) marshal() (x []byte) {
if m.raw != nil {
return m.raw
@@ -698,6 +792,16 @@ type nextProtoMsg struct {
proto string
}
+func (m *nextProtoMsg) equal(i interface{}) bool {
+ m1, ok := i.(*nextProtoMsg)
+ if !ok {
+ return false
+ }
+
+ return bytes.Equal(m.raw, m1.raw) &&
+ m.proto == m1.proto
+}
+
func (m *nextProtoMsg) marshal() []byte {
if m.raw != nil {
return m.raw
@@ -759,6 +863,17 @@ type certificateRequestMsg struct {
certificateAuthorities [][]byte
}
+func (m *certificateRequestMsg) equal(i interface{}) bool {
+ m1, ok := i.(*certificateRequestMsg)
+ if !ok {
+ return false
+ }
+
+ return bytes.Equal(m.raw, m1.raw) &&
+ bytes.Equal(m.certificateTypes, m1.certificateTypes) &&
+ eqByteSlices(m.certificateAuthorities, m1.certificateAuthorities)
+}
+
func (m *certificateRequestMsg) marshal() (x []byte) {
if m.raw != nil {
return m.raw
@@ -859,6 +974,16 @@ type certificateVerifyMsg struct {
signature []byte
}
+func (m *certificateVerifyMsg) equal(i interface{}) bool {
+ m1, ok := i.(*certificateVerifyMsg)
+ if !ok {
+ return false
+ }
+
+ return bytes.Equal(m.raw, m1.raw) &&
+ bytes.Equal(m.signature, m1.signature)
+}
+
func (m *certificateVerifyMsg) marshal() (x []byte) {
if m.raw != nil {
return m.raw
@@ -902,3 +1027,39 @@ func (m *certificateVerifyMsg) unmarshal(data []byte) bool {
return true
}
+
+func eqUint16s(x, y []uint16) bool {
+ if len(x) != len(y) {
+ return false
+ }
+ for i, v := range x {
+ if y[i] != v {
+ return false
+ }
+ }
+ return true
+}
+
+func eqStrings(x, y []string) bool {
+ if len(x) != len(y) {
+ return false
+ }
+ for i, v := range x {
+ if y[i] != v {
+ return false
+ }
+ }
+ return true
+}
+
+func eqByteSlices(x, y [][]byte) bool {
+ if len(x) != len(y) {
+ return false
+ }
+ for i, v := range x {
+ if !bytes.Equal(v, y[i]) {
+ return false
+ }
+ }
+ return true
+}
diff --git a/libgo/go/crypto/tls/handshake_messages_test.go b/libgo/go/crypto/tls/handshake_messages_test.go
index 87e8f7e428d..e62a9d581b3 100644
--- a/libgo/go/crypto/tls/handshake_messages_test.go
+++ b/libgo/go/crypto/tls/handshake_messages_test.go
@@ -27,10 +27,12 @@ var tests = []interface{}{
type testMessage interface {
marshal() []byte
unmarshal([]byte) bool
+ equal(interface{}) bool
}
func TestMarshalUnmarshal(t *testing.T) {
rand := rand.New(rand.NewSource(0))
+
for i, iface := range tests {
ty := reflect.ValueOf(iface).Type()
@@ -54,7 +56,7 @@ func TestMarshalUnmarshal(t *testing.T) {
}
m2.marshal() // to fill any marshal cache in the message
- if !reflect.DeepEqual(m1, m2) {
+ if !m1.equal(m2) {
t.Errorf("#%d got:%#v want:%#v %x", i, m2, m1, marshaled)
break
}
diff --git a/libgo/go/crypto/tls/root_windows.go b/libgo/go/crypto/tls/root_windows.go
index b8e27a9a5d2..13073dcee78 100644
--- a/libgo/go/crypto/tls/root_windows.go
+++ b/libgo/go/crypto/tls/root_windows.go
@@ -12,8 +12,8 @@ import (
)
func loadStore(roots *x509.CertPool, name string) {
- store, errno := syscall.CertOpenSystemStore(syscall.InvalidHandle, syscall.StringToUTF16Ptr(name))
- if errno != 0 {
+ store, err := syscall.CertOpenSystemStore(syscall.InvalidHandle, syscall.StringToUTF16Ptr(name))
+ if err != nil {
return
}
diff --git a/libgo/go/crypto/xtea/cipher.go b/libgo/go/crypto/xtea/cipher.go
index 64d933c2b67..3ed05814a3b 100644
--- a/libgo/go/crypto/xtea/cipher.go
+++ b/libgo/go/crypto/xtea/cipher.go
@@ -44,7 +44,7 @@ func NewCipher(key []byte) (*Cipher, error) {
}
// BlockSize returns the XTEA block size, 8 bytes.
-// It is necessary to satisfy the Cipher interface in the
+// It is necessary to satisfy the Block interface in the
// package "crypto/cipher".
func (c *Cipher) BlockSize() int { return BlockSize }
diff --git a/libgo/go/encoding/json/bench_test.go b/libgo/go/encoding/json/bench_test.go
new file mode 100644
index 00000000000..f0c52011a1d
--- /dev/null
+++ b/libgo/go/encoding/json/bench_test.go
@@ -0,0 +1,157 @@
+// 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.
+
+// Large data benchmark.
+// The JSON data is a summary of agl's changes in the
+// go, webkit, and chromium open source projects.
+// We benchmark converting between the JSON form
+// and in-memory data structures.
+
+package json
+
+import (
+ "bytes"
+ "compress/gzip"
+ "io/ioutil"
+ "os"
+ "testing"
+)
+
+type codeResponse struct {
+ Tree *codeNode `json:"tree"`
+ Username string `json:"username"`
+}
+
+type codeNode struct {
+ Name string `json:"name"`
+ Kids []*codeNode `json:"kids"`
+ CLWeight float64 `json:"cl_weight"`
+ Touches int `json:"touches"`
+ MinT int64 `json:"min_t"`
+ MaxT int64 `json:"max_t"`
+ MeanT int64 `json:"mean_t"`
+}
+
+var codeJSON []byte
+var codeStruct codeResponse
+
+func codeInit() {
+ f, err := os.Open("testdata/code.json.gz")
+ if err != nil {
+ panic(err)
+ }
+ defer f.Close()
+ gz, err := gzip.NewReader(f)
+ if err != nil {
+ panic(err)
+ }
+ data, err := ioutil.ReadAll(gz)
+ if err != nil {
+ panic(err)
+ }
+
+ codeJSON = data
+
+ if err := Unmarshal(codeJSON, &codeStruct); err != nil {
+ panic("unmarshal code.json: " + err.Error())
+ }
+
+ if data, err = Marshal(&codeStruct); err != nil {
+ panic("marshal code.json: " + err.Error())
+ }
+
+ if !bytes.Equal(data, codeJSON) {
+ println("different lengths", len(data), len(codeJSON))
+ for i := 0; i < len(data) && i < len(codeJSON); i++ {
+ if data[i] != codeJSON[i] {
+ println("re-marshal: changed at byte", i)
+ println("orig: ", string(codeJSON[i-10:i+10]))
+ println("new: ", string(data[i-10:i+10]))
+ break
+ }
+ }
+ panic("re-marshal code.json: different result")
+ }
+}
+
+func BenchmarkCodeEncoder(b *testing.B) {
+ if codeJSON == nil {
+ b.StopTimer()
+ codeInit()
+ b.StartTimer()
+ }
+ enc := NewEncoder(ioutil.Discard)
+ for i := 0; i < b.N; i++ {
+ if err := enc.Encode(&codeStruct); err != nil {
+ panic(err)
+ }
+ }
+ b.SetBytes(int64(len(codeJSON)))
+}
+
+func BenchmarkCodeMarshal(b *testing.B) {
+ if codeJSON == nil {
+ b.StopTimer()
+ codeInit()
+ b.StartTimer()
+ }
+ for i := 0; i < b.N; i++ {
+ if _, err := Marshal(&codeStruct); err != nil {
+ panic(err)
+ }
+ }
+ b.SetBytes(int64(len(codeJSON)))
+}
+
+func BenchmarkCodeDecoder(b *testing.B) {
+ if codeJSON == nil {
+ b.StopTimer()
+ codeInit()
+ b.StartTimer()
+ }
+ var buf bytes.Buffer
+ dec := NewDecoder(&buf)
+ var r codeResponse
+ for i := 0; i < b.N; i++ {
+ buf.Write(codeJSON)
+ // hide EOF
+ buf.WriteByte('\n')
+ buf.WriteByte('\n')
+ buf.WriteByte('\n')
+ if err := dec.Decode(&r); err != nil {
+ panic(err)
+ }
+ }
+ b.SetBytes(int64(len(codeJSON)))
+}
+
+func BenchmarkCodeUnmarshal(b *testing.B) {
+ if codeJSON == nil {
+ b.StopTimer()
+ codeInit()
+ b.StartTimer()
+ }
+ for i := 0; i < b.N; i++ {
+ var r codeResponse
+ if err := Unmarshal(codeJSON, &r); err != nil {
+ panic(err)
+ }
+ }
+ b.SetBytes(int64(len(codeJSON)))
+}
+
+func BenchmarkCodeUnmarshalReuse(b *testing.B) {
+ if codeJSON == nil {
+ b.StopTimer()
+ codeInit()
+ b.StartTimer()
+ }
+ var r codeResponse
+ for i := 0; i < b.N; i++ {
+ if err := Unmarshal(codeJSON, &r); err != nil {
+ panic(err)
+ }
+ }
+ b.SetBytes(int64(len(codeJSON)))
+}
diff --git a/libgo/go/encoding/json/decode.go b/libgo/go/encoding/json/decode.go
index 41295d2d241..2ea06c50c27 100644
--- a/libgo/go/encoding/json/decode.go
+++ b/libgo/go/encoding/json/decode.go
@@ -227,7 +227,7 @@ func (d *decodeState) value(v reflect.Value) {
// d.scan thinks we're still at the beginning of the item.
// Feed in an empty string - the shortest, simplest value -
// so that it knows we got to the end of the value.
- if d.scan.step == stateRedo {
+ if d.scan.redo {
panic("redo")
}
d.scan.step(&d.scan, '"')
@@ -381,6 +381,7 @@ func (d *decodeState) array(v reflect.Value) {
d.error(errPhase)
}
}
+
if i < av.Len() {
if !sv.IsValid() {
// Array. Zero the rest.
@@ -392,6 +393,9 @@ func (d *decodeState) array(v reflect.Value) {
sv.SetLen(i)
}
}
+ if i == 0 && av.Kind() == reflect.Slice && sv.IsNil() {
+ sv.Set(reflect.MakeSlice(sv.Type(), 0, 0))
+ }
}
// object consumes an object from d.data[d.off-1:], decoding into the value v.
diff --git a/libgo/go/encoding/json/scanner.go b/libgo/go/encoding/json/scanner.go
index 179690464b9..2661f410e01 100644
--- a/libgo/go/encoding/json/scanner.go
+++ b/libgo/go/encoding/json/scanner.go
@@ -80,6 +80,9 @@ type scanner struct {
// on a 64-bit Mac Mini, and it's nicer to read.
step func(*scanner, int) int
+ // Reached end of top-level value.
+ endTop bool
+
// Stack of what we're in the middle of - array values, object keys, object values.
parseState []int
@@ -87,6 +90,7 @@ type scanner struct {
err error
// 1-byte redo (see undo method)
+ redo bool
redoCode int
redoState func(*scanner, int) int
@@ -135,6 +139,8 @@ func (s *scanner) reset() {
s.step = stateBeginValue
s.parseState = s.parseState[0:0]
s.err = nil
+ s.redo = false
+ s.endTop = false
}
// eof tells the scanner that the end of input has been reached.
@@ -143,11 +149,11 @@ func (s *scanner) eof() int {
if s.err != nil {
return scanError
}
- if s.step == stateEndTop {
+ if s.endTop {
return scanEnd
}
s.step(s, ' ')
- if s.step == stateEndTop {
+ if s.endTop {
return scanEnd
}
if s.err == nil {
@@ -166,8 +172,10 @@ func (s *scanner) pushParseState(p int) {
func (s *scanner) popParseState() {
n := len(s.parseState) - 1
s.parseState = s.parseState[0:n]
+ s.redo = false
if n == 0 {
s.step = stateEndTop
+ s.endTop = true
} else {
s.step = stateEndValue
}
@@ -269,6 +277,7 @@ func stateEndValue(s *scanner, c int) int {
if n == 0 {
// Completed top-level before the current byte.
s.step = stateEndTop
+ s.endTop = true
return stateEndTop(s, c)
}
if c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
@@ -606,16 +615,18 @@ func quoteChar(c int) string {
// undo causes the scanner to return scanCode from the next state transition.
// This gives callers a simple 1-byte undo mechanism.
func (s *scanner) undo(scanCode int) {
- if s.step == stateRedo {
- panic("invalid use of scanner")
+ if s.redo {
+ panic("json: invalid use of scanner")
}
s.redoCode = scanCode
s.redoState = s.step
s.step = stateRedo
+ s.redo = true
}
// stateRedo helps implement the scanner's 1-byte undo.
func stateRedo(s *scanner, c int) int {
+ s.redo = false
s.step = s.redoState
return s.redoCode
}
diff --git a/libgo/go/encoding/json/scanner_test.go b/libgo/go/encoding/json/scanner_test.go
index a0a5995af8f..14d850865a6 100644
--- a/libgo/go/encoding/json/scanner_test.go
+++ b/libgo/go/encoding/json/scanner_test.go
@@ -186,11 +186,12 @@ func TestNextValueBig(t *testing.T) {
}
}
+var benchScan scanner
+
func BenchmarkSkipValue(b *testing.B) {
initBig()
- var scan scanner
for i := 0; i < b.N; i++ {
- nextValue(jsonBig, &scan)
+ nextValue(jsonBig, &benchScan)
}
b.SetBytes(int64(len(jsonBig)))
}
diff --git a/libgo/go/encoding/xml/xml_test.go b/libgo/go/encoding/xml/xml_test.go
index 6c874fadb7a..bcb22afde00 100644
--- a/libgo/go/encoding/xml/xml_test.go
+++ b/libgo/go/encoding/xml/xml_test.go
@@ -7,7 +7,6 @@ package xml
import (
"bytes"
"io"
- "os"
"reflect"
"strings"
"testing"
@@ -43,17 +42,17 @@ var rawTokens = []Token{
CharData([]byte("World <>'\" 白鵬翔")),
EndElement{Name{"", "hello"}},
CharData([]byte("\n ")),
- StartElement{Name{"", "goodbye"}, nil},
+ StartElement{Name{"", "goodbye"}, []Attr{}},
EndElement{Name{"", "goodbye"}},
CharData([]byte("\n ")),
StartElement{Name{"", "outer"}, []Attr{{Name{"foo", "attr"}, "value"}, {Name{"xmlns", "tag"}, "ns4"}}},
CharData([]byte("\n ")),
- StartElement{Name{"", "inner"}, nil},
+ StartElement{Name{"", "inner"}, []Attr{}},
EndElement{Name{"", "inner"}},
CharData([]byte("\n ")),
EndElement{Name{"", "outer"}},
CharData([]byte("\n ")),
- StartElement{Name{"tag", "name"}, nil},
+ StartElement{Name{"tag", "name"}, []Attr{}},
CharData([]byte("\n ")),
CharData([]byte("Some text here.")),
CharData([]byte("\n ")),
@@ -77,17 +76,17 @@ var cookedTokens = []Token{
CharData([]byte("World <>'\" 白鵬翔")),
EndElement{Name{"ns2", "hello"}},
CharData([]byte("\n ")),
- StartElement{Name{"ns2", "goodbye"}, nil},
+ StartElement{Name{"ns2", "goodbye"}, []Attr{}},
EndElement{Name{"ns2", "goodbye"}},
CharData([]byte("\n ")),
StartElement{Name{"ns2", "outer"}, []Attr{{Name{"ns1", "attr"}, "value"}, {Name{"xmlns", "tag"}, "ns4"}}},
CharData([]byte("\n ")),
- StartElement{Name{"ns2", "inner"}, nil},
+ StartElement{Name{"ns2", "inner"}, []Attr{}},
EndElement{Name{"ns2", "inner"}},
CharData([]byte("\n ")),
EndElement{Name{"ns2", "outer"}},
CharData([]byte("\n ")),
- StartElement{Name{"ns3", "name"}, nil},
+ StartElement{Name{"ns3", "name"}, []Attr{}},
CharData([]byte("\n ")),
CharData([]byte("Some text here.")),
CharData([]byte("\n ")),
@@ -105,7 +104,7 @@ var rawTokensAltEncoding = []Token{
CharData([]byte("\n")),
ProcInst{"xml", []byte(`version="1.0" encoding="x-testing-uppercase"`)},
CharData([]byte("\n")),
- StartElement{Name{"", "tag"}, nil},
+ StartElement{Name{"", "tag"}, []Attr{}},
CharData([]byte("value")),
EndElement{Name{"", "tag"}},
}
@@ -205,7 +204,7 @@ func (d *downCaser) ReadByte() (c byte, err error) {
func (d *downCaser) Read(p []byte) (int, error) {
d.t.Fatalf("unexpected Read call on downCaser reader")
- return 0, os.EINVAL
+ panic("unreachable")
}
func TestRawTokenAltEncoding(t *testing.T) {
diff --git a/libgo/go/exp/inotify/inotify_linux.go b/libgo/go/exp/inotify/inotify_linux.go
index d6b7e8514e6..f12436618f2 100644
--- a/libgo/go/exp/inotify/inotify_linux.go
+++ b/libgo/go/exp/inotify/inotify_linux.go
@@ -105,9 +105,9 @@ func (w *Watcher) AddWatch(path string, flags uint32) error {
watchEntry.flags |= flags
flags |= syscall.IN_MASK_ADD
}
- wd, errno := syscall.InotifyAddWatch(w.fd, path, flags)
- if wd == -1 {
- return &os.PathError{"inotify_add_watch", path, os.Errno(errno)}
+ wd, err := syscall.InotifyAddWatch(w.fd, path, flags)
+ if err != nil {
+ return &os.PathError{"inotify_add_watch", path, err}
}
if !found {
@@ -139,14 +139,10 @@ func (w *Watcher) RemoveWatch(path string) error {
// readEvents reads from the inotify file descriptor, converts the
// received events into Event objects and sends them via the Event channel
func (w *Watcher) readEvents() {
- var (
- buf [syscall.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events
- n int // Number of bytes read with read()
- errno int // Syscall errno
- )
+ var buf [syscall.SizeofInotifyEvent * 4096]byte
for {
- n, errno = syscall.Read(w.fd, buf[0:])
+ n, err := syscall.Read(w.fd, buf[0:])
// See if there is a message on the "done" channel
var done bool
select {
@@ -156,16 +152,16 @@ func (w *Watcher) readEvents() {
// If EOF or a "done" message is received
if n == 0 || done {
- errno := syscall.Close(w.fd)
- if errno == -1 {
- w.Error <- os.NewSyscallError("close", errno)
+ err := syscall.Close(w.fd)
+ if err != nil {
+ w.Error <- os.NewSyscallError("close", err)
}
close(w.Event)
close(w.Error)
return
}
if n < 0 {
- w.Error <- os.NewSyscallError("read", errno)
+ w.Error <- os.NewSyscallError("read", err)
continue
}
if n < syscall.SizeofInotifyEvent {
diff --git a/libgo/go/exp/sql/convert.go b/libgo/go/exp/sql/convert.go
index e46cebe9a3d..48e281203be 100644
--- a/libgo/go/exp/sql/convert.go
+++ b/libgo/go/exp/sql/convert.go
@@ -14,6 +14,21 @@ import (
"strconv"
)
+// subsetTypeArgs takes a slice of arguments from callers of the sql
+// package and converts them into a slice of the driver package's
+// "subset types".
+func subsetTypeArgs(args []interface{}) ([]interface{}, error) {
+ out := make([]interface{}, len(args))
+ for n, arg := range args {
+ var err error
+ out[n], err = driver.DefaultParameterConverter.ConvertValue(arg)
+ if err != nil {
+ return nil, fmt.Errorf("sql: converting argument #%d's type: %v", n+1, err)
+ }
+ }
+ return out, nil
+}
+
// convertAssign copies to dest the value in src, converting it if possible.
// An error is returned if the copy would result in loss of information.
// dest should be a pointer type.
diff --git a/libgo/go/exp/sql/driver/driver.go b/libgo/go/exp/sql/driver/driver.go
index 6a51c342415..91a388421d1 100644
--- a/libgo/go/exp/sql/driver/driver.go
+++ b/libgo/go/exp/sql/driver/driver.go
@@ -36,19 +36,22 @@ type Driver interface {
Open(name string) (Conn, error)
}
-// Execer is an optional interface that may be implemented by a Driver
-// or a Conn.
-//
-// If a Driver does not implement Execer, the sql package's DB.Exec
-// method first obtains a free connection from its free pool or from
-// the driver's Open method. Execer should only be implemented by
-// drivers that can provide a more efficient implementation.
+// ErrSkip may be returned by some optional interfaces' methods to
+// indicate at runtime that the fast path is unavailable and the sql
+// package should continue as if the optional interface was not
+// implemented. ErrSkip is only supported where explicitly
+// documented.
+var ErrSkip = errors.New("driver: skip fast-path; continue as if unimplemented")
+
+// Execer is an optional interface that may be implemented by a Conn.
//
// If a Conn does not implement Execer, the db package's DB.Exec will
// first prepare a query, execute the statement, and then close the
// statement.
//
// All arguments are of a subset type as defined in the package docs.
+//
+// Exec may return ErrSkip.
type Execer interface {
Exec(query string, args []interface{}) (Result, error)
}
@@ -94,6 +97,9 @@ type Stmt interface {
Close() error
// NumInput returns the number of placeholder parameters.
+ // -1 means the driver doesn't know how to count the number of
+ // placeholders, so we won't sanity check input here and instead let the
+ // driver deal with errors.
NumInput() int
// Exec executes a query that doesn't return rows, such
@@ -135,6 +141,8 @@ type Rows interface {
// The dest slice may be populated with only with values
// of subset types defined above, but excluding string.
// All string values must be converted to []byte.
+ //
+ // Next should return io.EOF when there are no more rows.
Next(dest []interface{}) error
}
diff --git a/libgo/go/exp/sql/fakedb_test.go b/libgo/go/exp/sql/fakedb_test.go
index c8a19974d64..17028e2cc38 100644
--- a/libgo/go/exp/sql/fakedb_test.go
+++ b/libgo/go/exp/sql/fakedb_test.go
@@ -195,6 +195,29 @@ func (c *fakeConn) Close() error {
return nil
}
+func checkSubsetTypes(args []interface{}) error {
+ for n, arg := range args {
+ switch arg.(type) {
+ case int64, float64, bool, nil, []byte, string:
+ default:
+ return fmt.Errorf("fakedb_test: invalid argument #%d: %v, type %T", n+1, arg, arg)
+ }
+ }
+ return nil
+}
+
+func (c *fakeConn) Exec(query string, args []interface{}) (driver.Result, error) {
+ // This is an optional interface, but it's implemented here
+ // just to check that all the args of of the proper types.
+ // ErrSkip is returned so the caller acts as if we didn't
+ // implement this at all.
+ err := checkSubsetTypes(args)
+ if err != nil {
+ return nil, err
+ }
+ return nil, driver.ErrSkip
+}
+
func errf(msg string, args ...interface{}) error {
return errors.New("fakedb: " + fmt.Sprintf(msg, args...))
}
@@ -323,6 +346,11 @@ func (s *fakeStmt) Close() error {
}
func (s *fakeStmt) Exec(args []interface{}) (driver.Result, error) {
+ err := checkSubsetTypes(args)
+ if err != nil {
+ return nil, err
+ }
+
db := s.c.db
switch s.cmd {
case "WIPE":
@@ -377,6 +405,11 @@ func (s *fakeStmt) execInsert(args []interface{}) (driver.Result, error) {
}
func (s *fakeStmt) Query(args []interface{}) (driver.Rows, error) {
+ err := checkSubsetTypes(args)
+ if err != nil {
+ return nil, err
+ }
+
db := s.c.db
if len(args) != s.placeholders {
panic("error in pkg db; should only get here if size is correct")
diff --git a/libgo/go/exp/sql/sql.go b/libgo/go/exp/sql/sql.go
index 291af7f67dc..c055fdd68c6 100644
--- a/libgo/go/exp/sql/sql.go
+++ b/libgo/go/exp/sql/sql.go
@@ -88,8 +88,9 @@ type DB struct {
driver driver.Driver
dsn string
- mu sync.Mutex
+ mu sync.Mutex // protects freeConn and closed
freeConn []driver.Conn
+ closed bool
}
// Open opens a database specified by its database driver name and a
@@ -106,6 +107,22 @@ func Open(driverName, dataSourceName string) (*DB, error) {
return &DB{driver: driver, dsn: dataSourceName}, nil
}
+// Close closes the database, releasing any open resources.
+func (db *DB) Close() error {
+ db.mu.Lock()
+ defer db.mu.Unlock()
+ var err error
+ for _, c := range db.freeConn {
+ err1 := c.Close()
+ if err1 != nil {
+ err = err1
+ }
+ }
+ db.freeConn = nil
+ db.closed = true
+ return err
+}
+
func (db *DB) maxIdleConns() int {
const defaultMaxIdleConns = 2
// TODO(bradfitz): ask driver, if supported, for its default preference
@@ -116,6 +133,9 @@ func (db *DB) maxIdleConns() int {
// conn returns a newly-opened or cached driver.Conn
func (db *DB) conn() (driver.Conn, error) {
db.mu.Lock()
+ if db.closed {
+ return nil, errors.New("sql: database is closed")
+ }
if n := len(db.freeConn); n > 0 {
conn := db.freeConn[n-1]
db.freeConn = db.freeConn[:n-1]
@@ -140,11 +160,13 @@ func (db *DB) connIfFree(wanted driver.Conn) (conn driver.Conn, ok bool) {
}
func (db *DB) putConn(c driver.Conn) {
- if n := len(db.freeConn); n < db.maxIdleConns() {
+ db.mu.Lock()
+ defer db.mu.Unlock()
+ if n := len(db.freeConn); !db.closed && n < db.maxIdleConns() {
db.freeConn = append(db.freeConn, c)
return
}
- db.closeConn(c)
+ db.closeConn(c) // TODO(bradfitz): release lock before calling this?
}
func (db *DB) closeConn(c driver.Conn) {
@@ -180,17 +202,11 @@ func (db *DB) Prepare(query string) (*Stmt, error) {
// Exec executes a query without returning any rows.
func (db *DB) Exec(query string, args ...interface{}) (Result, error) {
- // Optional fast path, if the driver implements driver.Execer.
- if execer, ok := db.driver.(driver.Execer); ok {
- resi, err := execer.Exec(query, args)
- if err != nil {
- return nil, err
- }
- return result{resi}, nil
+ sargs, err := subsetTypeArgs(args)
+ if err != nil {
+ return nil, err
}
- // If the driver does not implement driver.Execer, we need
- // a connection.
ci, err := db.conn()
if err != nil {
return nil, err
@@ -198,11 +214,13 @@ func (db *DB) Exec(query string, args ...interface{}) (Result, error) {
defer db.putConn(ci)
if execer, ok := ci.(driver.Execer); ok {
- resi, err := execer.Exec(query, args)
- if err != nil {
- return nil, err
+ resi, err := execer.Exec(query, sargs)
+ if err != driver.ErrSkip {
+ if err != nil {
+ return nil, err
+ }
+ return result{resi}, nil
}
- return result{resi}, nil
}
sti, err := ci.Prepare(query)
@@ -210,7 +228,8 @@ func (db *DB) Exec(query string, args ...interface{}) (Result, error) {
return nil, err
}
defer sti.Close()
- resi, err := sti.Exec(args)
+
+ resi, err := sti.Exec(sargs)
if err != nil {
return nil, err
}
@@ -386,7 +405,13 @@ func (tx *Tx) Exec(query string, args ...interface{}) (Result, error) {
return nil, err
}
defer sti.Close()
- resi, err := sti.Exec(args)
+
+ sargs, err := subsetTypeArgs(args)
+ if err != nil {
+ return nil, err
+ }
+
+ resi, err := sti.Exec(sargs)
if err != nil {
return nil, err
}
@@ -449,7 +474,10 @@ func (s *Stmt) Exec(args ...interface{}) (Result, error) {
}
defer releaseConn()
- if want := si.NumInput(); len(args) != want {
+ // -1 means the driver doesn't know how to count the number of
+ // placeholders, so we won't sanity check input here and instead let the
+ // driver deal with errors.
+ if want := si.NumInput(); want != -1 && len(args) != want {
return nil, fmt.Errorf("db: expected %d arguments, got %d", want, len(args))
}
@@ -545,10 +573,18 @@ func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
if err != nil {
return nil, err
}
- if len(args) != si.NumInput() {
+
+ // -1 means the driver doesn't know how to count the number of
+ // placeholders, so we won't sanity check input here and instead let the
+ // driver deal with errors.
+ if want := si.NumInput(); want != -1 && len(args) != want {
return nil, fmt.Errorf("db: statement expects %d inputs; got %d", si.NumInput(), len(args))
}
- rowsi, err := si.Query(args)
+ sargs, err := subsetTypeArgs(args)
+ if err != nil {
+ return nil, err
+ }
+ rowsi, err := si.Query(sargs)
if err != nil {
s.db.putConn(ci)
return nil, err
diff --git a/libgo/go/exp/sql/sql_test.go b/libgo/go/exp/sql/sql_test.go
index eb1bb58966e..d365f6ba190 100644
--- a/libgo/go/exp/sql/sql_test.go
+++ b/libgo/go/exp/sql/sql_test.go
@@ -34,8 +34,16 @@ func exec(t *testing.T, db *DB, query string, args ...interface{}) {
}
}
+func closeDB(t *testing.T, db *DB) {
+ err := db.Close()
+ if err != nil {
+ t.Fatalf("error closing DB: %v", err)
+ }
+}
+
func TestQuery(t *testing.T) {
db := newTestDB(t, "people")
+ defer closeDB(t, db)
var name string
var age int
@@ -69,6 +77,7 @@ func TestQuery(t *testing.T) {
func TestStatementQueryRow(t *testing.T) {
db := newTestDB(t, "people")
+ defer closeDB(t, db)
stmt, err := db.Prepare("SELECT|people|age|name=?")
if err != nil {
t.Fatalf("Prepare: %v", err)
@@ -94,6 +103,7 @@ func TestStatementQueryRow(t *testing.T) {
// just a test of fakedb itself
func TestBogusPreboundParameters(t *testing.T) {
db := newTestDB(t, "foo")
+ defer closeDB(t, db)
exec(t, db, "CREATE|t1|name=string,age=int32,dead=bool")
_, err := db.Prepare("INSERT|t1|name=?,age=bogusconversion")
if err == nil {
@@ -106,6 +116,7 @@ func TestBogusPreboundParameters(t *testing.T) {
func TestDb(t *testing.T) {
db := newTestDB(t, "foo")
+ defer closeDB(t, db)
exec(t, db, "CREATE|t1|name=string,age=int32,dead=bool")
stmt, err := db.Prepare("INSERT|t1|name=?,age=?")
if err != nil {
diff --git a/libgo/go/exp/ssh/cipher.go b/libgo/go/exp/ssh/cipher.go
new file mode 100644
index 00000000000..de4926d7b81
--- /dev/null
+++ b/libgo/go/exp/ssh/cipher.go
@@ -0,0 +1,88 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/rc4"
+)
+
+// streamDump is used to dump the initial keystream for stream ciphers. It is a
+// a write-only buffer, and not intended for reading so do not require a mutex.
+var streamDump [512]byte
+
+// noneCipher implements cipher.Stream and provides no encryption. It is used
+// by the transport before the first key-exchange.
+type noneCipher struct{}
+
+func (c noneCipher) XORKeyStream(dst, src []byte) {
+ copy(dst, src)
+}
+
+func newAESCTR(key, iv []byte) (cipher.Stream, error) {
+ c, err := aes.NewCipher(key)
+ if err != nil {
+ return nil, err
+ }
+ return cipher.NewCTR(c, iv), nil
+}
+
+func newRC4(key, iv []byte) (cipher.Stream, error) {
+ return rc4.NewCipher(key)
+}
+
+type cipherMode struct {
+ keySize int
+ ivSize int
+ skip int
+ createFn func(key, iv []byte) (cipher.Stream, error)
+}
+
+func (c *cipherMode) createCipher(key, iv []byte) (cipher.Stream, error) {
+ if len(key) < c.keySize {
+ panic("ssh: key length too small for cipher")
+ }
+ if len(iv) < c.ivSize {
+ panic("ssh: iv too small for cipher")
+ }
+
+ stream, err := c.createFn(key[:c.keySize], iv[:c.ivSize])
+ if err != nil {
+ return nil, err
+ }
+
+ for remainingToDump := c.skip; remainingToDump > 0; {
+ dumpThisTime := remainingToDump
+ if dumpThisTime > len(streamDump) {
+ dumpThisTime = len(streamDump)
+ }
+ stream.XORKeyStream(streamDump[:dumpThisTime], streamDump[:dumpThisTime])
+ remainingToDump -= dumpThisTime
+ }
+
+ return stream, nil
+}
+
+// Specifies a default set of ciphers and a preference order. This is based on
+// OpenSSH's default client preference order, minus algorithms that are not
+// implemented.
+var DefaultCipherOrder = []string{
+ "aes128-ctr", "aes192-ctr", "aes256-ctr",
+ "arcfour256", "arcfour128",
+}
+
+var cipherModes = map[string]*cipherMode{
+ // Ciphers from RFC4344, which introduced many CTR-based ciphers. Algorithms
+ // are defined in the order specified in the RFC.
+ "aes128-ctr": &cipherMode{16, aes.BlockSize, 0, newAESCTR},
+ "aes192-ctr": &cipherMode{24, aes.BlockSize, 0, newAESCTR},
+ "aes256-ctr": &cipherMode{32, aes.BlockSize, 0, newAESCTR},
+
+ // Ciphers from RFC4345, which introduces security-improved arcfour ciphers.
+ // They are defined in the order specified in the RFC.
+ "arcfour128": &cipherMode{16, 0, 1536, newRC4},
+ "arcfour256": &cipherMode{32, 0, 1536, newRC4},
+}
diff --git a/libgo/go/exp/ssh/cipher_test.go b/libgo/go/exp/ssh/cipher_test.go
new file mode 100644
index 00000000000..ea27bd8a803
--- /dev/null
+++ b/libgo/go/exp/ssh/cipher_test.go
@@ -0,0 +1,62 @@
+// 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 ssh
+
+import (
+ "bytes"
+ "testing"
+)
+
+// TestCipherReversal tests that each cipher factory produces ciphers that can
+// encrypt and decrypt some data successfully.
+func TestCipherReversal(t *testing.T) {
+ testData := []byte("abcdefghijklmnopqrstuvwxyz012345")
+ testKey := []byte("AbCdEfGhIjKlMnOpQrStUvWxYz012345")
+ testIv := []byte("sdflkjhsadflkjhasdflkjhsadfklhsa")
+
+ cryptBuffer := make([]byte, 32)
+
+ for name, cipherMode := range cipherModes {
+ encrypter, err := cipherMode.createCipher(testKey, testIv)
+ if err != nil {
+ t.Errorf("failed to create encrypter for %q: %s", name, err)
+ continue
+ }
+ decrypter, err := cipherMode.createCipher(testKey, testIv)
+ if err != nil {
+ t.Errorf("failed to create decrypter for %q: %s", name, err)
+ continue
+ }
+
+ copy(cryptBuffer, testData)
+
+ encrypter.XORKeyStream(cryptBuffer, cryptBuffer)
+ if name == "none" {
+ if !bytes.Equal(cryptBuffer, testData) {
+ t.Errorf("encryption made change with 'none' cipher")
+ continue
+ }
+ } else {
+ if bytes.Equal(cryptBuffer, testData) {
+ t.Errorf("encryption made no change with %q", name)
+ continue
+ }
+ }
+
+ decrypter.XORKeyStream(cryptBuffer, cryptBuffer)
+ if !bytes.Equal(cryptBuffer, testData) {
+ t.Errorf("decrypted bytes not equal to input with %q", name)
+ continue
+ }
+ }
+}
+
+func TestDefaultCiphersExist(t *testing.T) {
+ for _, cipherAlgo := range DefaultCipherOrder {
+ if _, ok := cipherModes[cipherAlgo]; !ok {
+ t.Errorf("default cipher %q is unknown", cipherAlgo)
+ }
+ }
+}
diff --git a/libgo/go/exp/ssh/client.go b/libgo/go/exp/ssh/client.go
index da45688eee0..24569ad9389 100644
--- a/libgo/go/exp/ssh/client.go
+++ b/libgo/go/exp/ssh/client.go
@@ -35,10 +35,6 @@ func Client(c net.Conn, config *ClientConfig) (*ClientConn, error) {
conn.Close()
return nil, err
}
- if err := conn.authenticate(); err != nil {
- conn.Close()
- return nil, err
- }
go conn.mainLoop()
return conn, nil
}
@@ -64,8 +60,8 @@ func (c *ClientConn) handshake() error {
clientKexInit := kexInitMsg{
KexAlgos: supportedKexAlgos,
ServerHostKeyAlgos: supportedHostKeyAlgos,
- CiphersClientServer: supportedCiphers,
- CiphersServerClient: supportedCiphers,
+ CiphersClientServer: c.config.Crypto.ciphers(),
+ CiphersServerClient: c.config.Crypto.ciphers(),
MACsClientServer: supportedMACs,
MACsServerClient: supportedMACs,
CompressionClientServer: supportedCompressions,
@@ -128,7 +124,10 @@ func (c *ClientConn) handshake() error {
if packet[0] != msgNewKeys {
return UnexpectedMessageError{msgNewKeys, packet[0]}
}
- return c.transport.reader.setupKeys(serverKeys, K, H, H, hashFunc)
+ if err := c.transport.reader.setupKeys(serverKeys, K, H, H, hashFunc); err != nil {
+ return err
+ }
+ return c.authenticate(H)
}
// kexDH performs Diffie-Hellman key agreement on a ClientConn. The
@@ -195,6 +194,7 @@ func (c *ClientConn) openChan(typ string) (*clientChan, error) {
switch msg := (<-ch.msg).(type) {
case *channelOpenConfirmMsg:
ch.peersId = msg.MyId
+ ch.win <- int(msg.MyWindow)
case *channelOpenFailureMsg:
c.chanlist.remove(ch.id)
return nil, errors.New(msg.Message)
@@ -301,6 +301,9 @@ type ClientConfig struct {
// A slice of ClientAuth methods. Only the first instance
// of a particular RFC 4252 method will be used during authentication.
Auth []ClientAuth
+
+ // Cryptographic-related configuration.
+ Crypto CryptoConfig
}
func (c *ClientConfig) rand() io.Reader {
diff --git a/libgo/go/exp/ssh/client_auth.go b/libgo/go/exp/ssh/client_auth.go
index 0089d0c769e..25f9e216225 100644
--- a/libgo/go/exp/ssh/client_auth.go
+++ b/libgo/go/exp/ssh/client_auth.go
@@ -6,10 +6,11 @@ package ssh
import (
"errors"
+ "io"
)
// authenticate authenticates with the remote server. See RFC 4252.
-func (c *ClientConn) authenticate() error {
+func (c *ClientConn) authenticate(session []byte) error {
// initiate user auth session
if err := c.writePacket(marshal(msgServiceRequest, serviceRequestMsg{serviceUserAuth})); err != nil {
return err
@@ -26,7 +27,7 @@ func (c *ClientConn) authenticate() error {
// then any untried methods suggested by the server.
tried, remain := make(map[string]bool), make(map[string]bool)
for auth := ClientAuth(new(noneAuth)); auth != nil; {
- ok, methods, err := auth.auth(c.config.User, c.transport)
+ ok, methods, err := auth.auth(session, c.config.User, c.transport, c.config.rand())
if err != nil {
return err
}
@@ -60,7 +61,7 @@ type ClientAuth interface {
// Returns true if authentication is successful.
// If authentication is not successful, a []string of alternative
// method names is returned.
- auth(user string, t *transport) (bool, []string, error)
+ auth(session []byte, user string, t *transport, rand io.Reader) (bool, []string, error)
// method returns the RFC 4252 method name.
method() string
@@ -69,7 +70,7 @@ type ClientAuth interface {
// "none" authentication, RFC 4252 section 5.2.
type noneAuth int
-func (n *noneAuth) auth(user string, t *transport) (bool, []string, error) {
+func (n *noneAuth) auth(session []byte, user string, t *transport, rand io.Reader) (bool, []string, error) {
if err := t.writePacket(marshal(msgUserAuthRequest, userAuthRequestMsg{
User: user,
Service: serviceSSH,
@@ -102,7 +103,7 @@ type passwordAuth struct {
ClientPassword
}
-func (p *passwordAuth) auth(user string, t *transport) (bool, []string, error) {
+func (p *passwordAuth) auth(session []byte, user string, t *transport, rand io.Reader) (bool, []string, error) {
type passwordAuthMsg struct {
User string
Service string
@@ -155,3 +156,140 @@ type ClientPassword interface {
func ClientAuthPassword(impl ClientPassword) ClientAuth {
return &passwordAuth{impl}
}
+
+// ClientKeyring implements access to a client key ring.
+type ClientKeyring interface {
+ // Key returns the i'th rsa.Publickey or dsa.Publickey, or nil if
+ // no key exists at i.
+ Key(i int) (key interface{}, err error)
+
+ // Sign returns a signature of the given data using the i'th key
+ // and the supplied random source.
+ Sign(i int, rand io.Reader, data []byte) (sig []byte, err error)
+}
+
+// "publickey" authentication, RFC 4252 Section 7.
+type publickeyAuth struct {
+ ClientKeyring
+}
+
+func (p *publickeyAuth) auth(session []byte, user string, t *transport, rand io.Reader) (bool, []string, error) {
+ type publickeyAuthMsg struct {
+ User string
+ Service string
+ Method string
+ // HasSig indicates to the reciver packet that the auth request is signed and
+ // should be used for authentication of the request.
+ HasSig bool
+ Algoname string
+ Pubkey string
+ // Sig is defined as []byte so marshal will exclude it during the query phase
+ Sig []byte `ssh:"rest"`
+ }
+
+ // Authentication is performed in two stages. The first stage sends an
+ // enquiry to test if each key is acceptable to the remote. The second
+ // stage attempts to authenticate with the valid keys obtained in the
+ // first stage.
+
+ var index int
+ // a map of public keys to their index in the keyring
+ validKeys := make(map[int]interface{})
+ for {
+ key, err := p.Key(index)
+ if err != nil {
+ return false, nil, err
+ }
+ if key == nil {
+ // no more keys in the keyring
+ break
+ }
+ pubkey := serializePublickey(key)
+ algoname := algoName(key)
+ msg := publickeyAuthMsg{
+ User: user,
+ Service: serviceSSH,
+ Method: p.method(),
+ HasSig: false,
+ Algoname: algoname,
+ Pubkey: string(pubkey),
+ }
+ if err := t.writePacket(marshal(msgUserAuthRequest, msg)); err != nil {
+ return false, nil, err
+ }
+ packet, err := t.readPacket()
+ if err != nil {
+ return false, nil, err
+ }
+ switch packet[0] {
+ case msgUserAuthPubKeyOk:
+ msg := decode(packet).(*userAuthPubKeyOkMsg)
+ if msg.Algo != algoname || msg.PubKey != string(pubkey) {
+ continue
+ }
+ validKeys[index] = key
+ case msgUserAuthFailure:
+ default:
+ return false, nil, UnexpectedMessageError{msgUserAuthSuccess, packet[0]}
+ }
+ index++
+ }
+
+ // methods that may continue if this auth is not successful.
+ var methods []string
+ for i, key := range validKeys {
+ pubkey := serializePublickey(key)
+ algoname := algoName(key)
+ sign, err := p.Sign(i, rand, buildDataSignedForAuth(session, userAuthRequestMsg{
+ User: user,
+ Service: serviceSSH,
+ Method: p.method(),
+ }, []byte(algoname), pubkey))
+ if err != nil {
+ return false, nil, err
+ }
+ // manually wrap the serialized signature in a string
+ s := serializeSignature(algoname, sign)
+ sig := make([]byte, stringLength(s))
+ marshalString(sig, s)
+ msg := publickeyAuthMsg{
+ User: user,
+ Service: serviceSSH,
+ Method: p.method(),
+ HasSig: true,
+ Algoname: algoname,
+ Pubkey: string(pubkey),
+ Sig: sig,
+ }
+ p := marshal(msgUserAuthRequest, msg)
+ if err := t.writePacket(p); err != nil {
+ return false, nil, err
+ }
+ packet, err := t.readPacket()
+ if err != nil {
+ return false, nil, err
+ }
+ switch packet[0] {
+ case msgUserAuthSuccess:
+ return true, nil, nil
+ case msgUserAuthFailure:
+ msg := decode(packet).(*userAuthFailureMsg)
+ methods = msg.Methods
+ continue
+ case msgDisconnect:
+ return false, nil, io.EOF
+ default:
+ return false, nil, UnexpectedMessageError{msgUserAuthSuccess, packet[0]}
+ }
+ }
+ return false, methods, nil
+}
+
+func (p *publickeyAuth) method() string {
+ return "publickey"
+}
+
+// ClientAuthPublickey returns a ClientAuth using public key authentication.
+func ClientAuthPublickey(impl ClientKeyring) ClientAuth {
+ return &publickeyAuth{impl}
+}
diff --git a/libgo/go/exp/ssh/client_auth_test.go b/libgo/go/exp/ssh/client_auth_test.go
new file mode 100644
index 00000000000..6467f578356
--- /dev/null
+++ b/libgo/go/exp/ssh/client_auth_test.go
@@ -0,0 +1,248 @@
+// 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 ssh
+
+import (
+ "bytes"
+ "crypto"
+ "crypto/rand"
+ "crypto/rsa"
+ "crypto/x509"
+ "encoding/pem"
+ "errors"
+ "io"
+ "io/ioutil"
+ "testing"
+)
+
+const _pem = `-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEA19lGVsTqIT5iiNYRgnoY1CwkbETW5cq+Rzk5v/kTlf31XpSU
+70HVWkbTERECjaYdXM2gGcbb+sxpq6GtXf1M3kVomycqhxwhPv4Cr6Xp4WT/jkFx
+9z+FFzpeodGJWjOH6L2H5uX1Cvr9EDdQp9t9/J32/qBFntY8GwoUI/y/1MSTmMiF
+tupdMODN064vd3gyMKTwrlQ8tZM6aYuyOPsutLlUY7M5x5FwMDYvnPDSeyT/Iw0z
+s3B+NCyqeeMd2T7YzQFnRATj0M7rM5LoSs7DVqVriOEABssFyLj31PboaoLhOKgc
+qoM9khkNzr7FHVvi+DhYM2jD0DwvqZLN6NmnLwIDAQABAoIBAQCGVj+kuSFOV1lT
++IclQYA6bM6uY5mroqcSBNegVxCNhWU03BxlW//BE9tA/+kq53vWylMeN9mpGZea
+riEMIh25KFGWXqXlOOioH8bkMsqA8S7sBmc7jljyv+0toQ9vCCtJ+sueNPhxQQxH
+D2YvUjfzBQ04I9+wn30BByDJ1QA/FoPsunxIOUCcRBE/7jxuLYcpR+JvEF68yYIh
+atXRld4W4in7T65YDR8jK1Uj9XAcNeDYNpT/M6oFLx1aPIlkG86aCWRO19S1jLPT
+b1ZAKHHxPMCVkSYW0RqvIgLXQOR62D0Zne6/2wtzJkk5UCjkSQ2z7ZzJpMkWgDgN
+ifCULFPBAoGBAPoMZ5q1w+zB+knXUD33n1J+niN6TZHJulpf2w5zsW+m2K6Zn62M
+MXndXlVAHtk6p02q9kxHdgov34Uo8VpuNjbS1+abGFTI8NZgFo+bsDxJdItemwC4
+KJ7L1iz39hRN/ZylMRLz5uTYRGddCkeIHhiG2h7zohH/MaYzUacXEEy3AoGBANz8
+e/msleB+iXC0cXKwds26N4hyMdAFE5qAqJXvV3S2W8JZnmU+sS7vPAWMYPlERPk1
+D8Q2eXqdPIkAWBhrx4RxD7rNc5qFNcQWEhCIxC9fccluH1y5g2M+4jpMX2CT8Uv+
+3z+NoJ5uDTXZTnLCfoZzgZ4nCZVZ+6iU5U1+YXFJAoGBANLPpIV920n/nJmmquMj
+orI1R/QXR9Cy56cMC65agezlGOfTYxk5Cfl5Ve+/2IJCfgzwJyjWUsFx7RviEeGw
+64o7JoUom1HX+5xxdHPsyZ96OoTJ5RqtKKoApnhRMamau0fWydH1yeOEJd+TRHhc
+XStGfhz8QNa1dVFvENczja1vAoGABGWhsd4VPVpHMc7lUvrf4kgKQtTC2PjA4xoc
+QJ96hf/642sVE76jl+N6tkGMzGjnVm4P2j+bOy1VvwQavKGoXqJBRd5Apppv727g
+/SM7hBXKFc/zH80xKBBgP/i1DR7kdjakCoeu4ngeGywvu2jTS6mQsqzkK+yWbUxJ
+I7mYBsECgYB/KNXlTEpXtz/kwWCHFSYA8U74l7zZbVD8ul0e56JDK+lLcJ0tJffk
+gqnBycHj6AhEycjda75cs+0zybZvN4x65KZHOGW/O/7OAWEcZP5TPb3zf9ned3Hl
+NsZoFj52ponUM6+99A2CmezFCN16c4mbA//luWF+k3VVqR6BpkrhKw==
+-----END RSA PRIVATE KEY-----`
+
+// reused internally by tests
+var serverConfig = new(ServerConfig)
+
+func init() {
+ if err := serverConfig.SetRSAPrivateKey([]byte(_pem)); err != nil {
+ panic("unable to set private key: " + err.Error())
+ }
+}
+
+// keychain implements the ClientPublickey interface
+type keychain struct {
+ keys []*rsa.PrivateKey
+}
+
+func (k *keychain) Key(i int) (interface{}, error) {
+ if i < 0 || i >= len(k.keys) {
+ return nil, nil
+ }
+ return k.keys[i].PublicKey, nil
+}
+
+func (k *keychain) Sign(i int, rand io.Reader, data []byte) (sig []byte, err error) {
+ hashFunc := crypto.SHA1
+ h := hashFunc.New()
+ h.Write(data)
+ digest := h.Sum()
+ return rsa.SignPKCS1v15(rand, k.keys[i], hashFunc, digest)
+}
+
+func (k *keychain) loadPEM(file string) error {
+ buf, err := ioutil.ReadFile(file)
+ if err != nil {
+ return err
+ }
+ block, _ := pem.Decode(buf)
+ if block == nil {
+ return errors.New("ssh: no key found")
+ }
+ r, err := x509.ParsePKCS1PrivateKey(block.Bytes)
+ if err != nil {
+ return err
+ }
+ k.keys = append(k.keys, r)
+ return nil
+}
+
+var pkey *rsa.PrivateKey
+
+func init() {
+ var err error
+ pkey, err = rsa.GenerateKey(rand.Reader, 512)
+ if err != nil {
+ panic("unable to generate public key")
+ }
+}
+
+func TestClientAuthPublickey(t *testing.T) {
+ k := new(keychain)
+ k.keys = append(k.keys, pkey)
+
+ serverConfig.PubKeyCallback = func(user, algo string, pubkey []byte) bool {
+ expected := []byte(serializePublickey(k.keys[0].PublicKey))
+ algoname := algoName(k.keys[0].PublicKey)
+ return user == "testuser" && algo == algoname && bytes.Equal(pubkey, expected)
+ }
+ serverConfig.PasswordCallback = nil
+
+ l, err := Listen("tcp", "127.0.0.1:0", serverConfig)
+ if err != nil {
+ t.Fatalf("unable to listen: %s", err)
+ }
+ defer l.Close()
+
+ done := make(chan bool, 1)
+ go func() {
+ c, err := l.Accept()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer c.Close()
+ if err := c.Handshake(); err != nil {
+ t.Error(err)
+ }
+ done <- true
+ }()
+
+ config := &ClientConfig{
+ User: "testuser",
+ Auth: []ClientAuth{
+ ClientAuthPublickey(k),
+ },
+ }
+
+ c, err := Dial("tcp", l.Addr().String(), config)
+ if err != nil {
+ t.Fatalf("unable to dial remote side: %s", err)
+ }
+ defer c.Close()
+ <-done
+}
+
+// password implements the ClientPassword interface
+type password string
+
+func (p password) Password(user string) (string, error) {
+ return string(p), nil
+}
+
+func TestClientAuthPassword(t *testing.T) {
+ pw := password("tiger")
+
+ serverConfig.PasswordCallback = func(user, pass string) bool {
+ return user == "testuser" && pass == string(pw)
+ }
+ serverConfig.PubKeyCallback = nil
+
+ l, err := Listen("tcp", "127.0.0.1:0", serverConfig)
+ if err != nil {
+ t.Fatalf("unable to listen: %s", err)
+ }
+ defer l.Close()
+
+ done := make(chan bool)
+ go func() {
+ c, err := l.Accept()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err := c.Handshake(); err != nil {
+ t.Error(err)
+ }
+ defer c.Close()
+ done <- true
+ }()
+
+ config := &ClientConfig{
+ User: "testuser",
+ Auth: []ClientAuth{
+ ClientAuthPassword(pw),
+ },
+ }
+
+ c, err := Dial("tcp", l.Addr().String(), config)
+ if err != nil {
+ t.Fatalf("unable to dial remote side: %s", err)
+ }
+ defer c.Close()
+ <-done
+}
+
+func TestClientAuthPasswordAndPublickey(t *testing.T) {
+ pw := password("tiger")
+
+ serverConfig.PasswordCallback = func(user, pass string) bool {
+ return user == "testuser" && pass == string(pw)
+ }
+
+ k := new(keychain)
+ k.keys = append(k.keys, pkey)
+
+ serverConfig.PubKeyCallback = func(user, algo string, pubkey []byte) bool {
+ expected := []byte(serializePublickey(k.keys[0].PublicKey))
+ algoname := algoName(k.keys[0].PublicKey)
+ return user == "testuser" && algo == algoname && bytes.Equal(pubkey, expected)
+ }
+
+ l, err := Listen("tcp", "127.0.0.1:0", serverConfig)
+ if err != nil {
+ t.Fatalf("unable to listen: %s", err)
+ }
+ defer l.Close()
+
+ done := make(chan bool)
+ go func() {
+ c, err := l.Accept()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err := c.Handshake(); err != nil {
+ t.Error(err)
+ }
+ defer c.Close()
+ done <- true
+ }()
+
+ wrongPw := password("wrong")
+ config := &ClientConfig{
+ User: "testuser",
+ Auth: []ClientAuth{
+ ClientAuthPassword(wrongPw),
+ ClientAuthPublickey(k),
+ },
+ }
+
+ c, err := Dial("tcp", l.Addr().String(), config)
+ if err != nil {
+ t.Fatalf("unable to dial remote side: %s", err)
+ }
+ defer c.Close()
+ <-done
+}
diff --git a/libgo/go/exp/ssh/client_func_test.go b/libgo/go/exp/ssh/client_func_test.go
new file mode 100644
index 00000000000..137456095a0
--- /dev/null
+++ b/libgo/go/exp/ssh/client_func_test.go
@@ -0,0 +1,61 @@
+// 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 ssh
+
+// ClientConn functional tests.
+// These tests require a running ssh server listening on port 22
+// on the local host. Functional tests will be skipped unless
+// -ssh.user and -ssh.pass must be passed to gotest.
+
+import (
+ "flag"
+ "testing"
+)
+
+var (
+ sshuser = flag.String("ssh.user", "", "ssh username")
+ sshpass = flag.String("ssh.pass", "", "ssh password")
+ sshprivkey = flag.String("ssh.privkey", "", "ssh privkey file")
+)
+
+func TestFuncPasswordAuth(t *testing.T) {
+ if *sshuser == "" {
+ t.Log("ssh.user not defined, skipping test")
+ return
+ }
+ config := &ClientConfig{
+ User: *sshuser,
+ Auth: []ClientAuth{
+ ClientAuthPassword(password(*sshpass)),
+ },
+ }
+ conn, err := Dial("tcp", "localhost:22", config)
+ if err != nil {
+ t.Fatalf("Unable to connect: %s", err)
+ }
+ defer conn.Close()
+}
+
+func TestFuncPublickeyAuth(t *testing.T) {
+ if *sshuser == "" {
+ t.Log("ssh.user not defined, skipping test")
+ return
+ }
+ kc := new(keychain)
+ if err := kc.loadPEM(*sshprivkey); err != nil {
+ t.Fatalf("unable to load private key: %s", err)
+ }
+ config := &ClientConfig{
+ User: *sshuser,
+ Auth: []ClientAuth{
+ ClientAuthPublickey(kc),
+ },
+ }
+ conn, err := Dial("tcp", "localhost:22", config)
+ if err != nil {
+ t.Fatalf("unable to connect: %s", err)
+ }
+ defer conn.Close()
+}
diff --git a/libgo/go/exp/ssh/common.go b/libgo/go/exp/ssh/common.go
index 273820b6428..01c55219d47 100644
--- a/libgo/go/exp/ssh/common.go
+++ b/libgo/go/exp/ssh/common.go
@@ -5,6 +5,8 @@
package ssh
import (
+ "crypto/dsa"
+ "crypto/rsa"
"math/big"
"strconv"
"sync"
@@ -14,7 +16,6 @@ import (
const (
kexAlgoDH14SHA1 = "diffie-hellman-group14-sha1"
hostAlgoRSA = "ssh-rsa"
- cipherAES128CTR = "aes128-ctr"
macSHA196 = "hmac-sha1-96"
compressionNone = "none"
serviceUserAuth = "ssh-userauth"
@@ -23,7 +24,6 @@ const (
var supportedKexAlgos = []string{kexAlgoDH14SHA1}
var supportedHostKeyAlgos = []string{hostAlgoRSA}
-var supportedCiphers = []string{cipherAES128CTR}
var supportedMACs = []string{macSHA196}
var supportedCompressions = []string{compressionNone}
@@ -127,3 +127,100 @@ func findAgreedAlgorithms(transport *transport, clientKexInit, serverKexInit *ke
ok = true
return
}
+
+// Cryptographic configuration common to both ServerConfig and ClientConfig.
+type CryptoConfig struct {
+ // The allowed cipher algorithms. If unspecified then DefaultCipherOrder is
+ // used.
+ Ciphers []string
+}
+
+func (c *CryptoConfig) ciphers() []string {
+ if c.Ciphers == nil {
+ return DefaultCipherOrder
+ }
+ return c.Ciphers
+}
+
+// serialize a signed slice according to RFC 4254 6.6.
+func serializeSignature(algoname string, sig []byte) []byte {
+ length := stringLength([]byte(algoname))
+ length += stringLength(sig)
+
+ ret := make([]byte, length)
+ r := marshalString(ret, []byte(algoname))
+ r = marshalString(r, sig)
+
+ return ret
+}
+
+// serialize an rsa.PublicKey or dsa.PublicKey according to RFC 4253 6.6.
+func serializePublickey(key interface{}) []byte {
+ algoname := algoName(key)
+ switch key := key.(type) {
+ case rsa.PublicKey:
+ e := new(big.Int).SetInt64(int64(key.E))
+ length := stringLength([]byte(algoname))
+ length += intLength(e)
+ length += intLength(key.N)
+ ret := make([]byte, length)
+ r := marshalString(ret, []byte(algoname))
+ r = marshalInt(r, e)
+ marshalInt(r, key.N)
+ return ret
+ case dsa.PublicKey:
+ length := stringLength([]byte(algoname))
+ length += intLength(key.P)
+ length += intLength(key.Q)
+ length += intLength(key.G)
+ length += intLength(key.Y)
+ ret := make([]byte, length)
+ r := marshalString(ret, []byte(algoname))
+ r = marshalInt(r, key.P)
+ r = marshalInt(r, key.Q)
+ r = marshalInt(r, key.G)
+ marshalInt(r, key.Y)
+ return ret
+ }
+ panic("unexpected key type")
+}
+
+func algoName(key interface{}) string {
+ switch key.(type) {
+ case rsa.PublicKey:
+ return "ssh-rsa"
+ case dsa.PublicKey:
+ return "ssh-dss"
+ }
+ panic("unexpected key type")
+}
+
+// buildDataSignedForAuth returns the data that is signed in order to prove
+// posession of a private key. See RFC 4252, section 7.
+func buildDataSignedForAuth(sessionId []byte, req userAuthRequestMsg, algo, pubKey []byte) []byte {
+ user := []byte(req.User)
+ service := []byte(req.Service)
+ method := []byte(req.Method)
+
+ length := stringLength(sessionId)
+ length += 1
+ length += stringLength(user)
+ length += stringLength(service)
+ length += stringLength(method)
+ length += 1
+ length += stringLength(algo)
+ length += stringLength(pubKey)
+
+ ret := make([]byte, length)
+ r := marshalString(ret, sessionId)
+ r[0] = msgUserAuthRequest
+ r = r[1:]
+ r = marshalString(r, user)
+ r = marshalString(r, service)
+ r = marshalString(r, method)
+ r[0] = 1
+ r = r[1:]
+ r = marshalString(r, algo)
+ r = marshalString(r, pubKey)
+ return ret
+}
diff --git a/libgo/go/exp/ssh/messages.go b/libgo/go/exp/ssh/messages.go
index e24b6398b56..cebb5609db3 100644
--- a/libgo/go/exp/ssh/messages.go
+++ b/libgo/go/exp/ssh/messages.go
@@ -392,7 +392,10 @@ func parseString(in []byte) (out, rest []byte, ok bool) {
return
}
-var comma = []byte{','}
+var (
+ comma = []byte{','}
+ emptyNameList = []string{}
+)
func parseNameList(in []byte) (out []string, rest []byte, ok bool) {
contents, rest, ok := parseString(in)
@@ -400,6 +403,7 @@ func parseNameList(in []byte) (out []string, rest []byte, ok bool) {
return
}
if len(contents) == 0 {
+ out = emptyNameList
return
}
parts := bytes.Split(contents, comma)
@@ -444,8 +448,6 @@ func parseUint32(in []byte) (out uint32, rest []byte, ok bool) {
return
}
-const maxPacketSize = 36000
-
func nameListLength(namelist []string) int {
length := 4 /* uint32 length prefix */
for i, name := range namelist {
diff --git a/libgo/go/exp/ssh/server.go b/libgo/go/exp/ssh/server.go
index 62035d52b7d..428a747e1e0 100644
--- a/libgo/go/exp/ssh/server.go
+++ b/libgo/go/exp/ssh/server.go
@@ -40,6 +40,9 @@ type ServerConfig struct {
// key authentication. It must return true iff the given public key is
// valid for the given user.
PubKeyCallback func(user, algo string, pubkey []byte) bool
+
+ // Cryptographic-related configuration.
+ Crypto CryptoConfig
}
func (c *ServerConfig) rand() io.Reader {
@@ -221,7 +224,7 @@ func (s *ServerConn) kexDH(group *dhGroup, hashFunc crypto.Hash, magics *handsha
return nil, nil, errors.New("internal error")
}
- serializedSig := serializeRSASignature(sig)
+ serializedSig := serializeSignature(hostAlgoRSA, sig)
kexDHReply := kexDHReplyMsg{
HostKey: serializedHostKey,
@@ -234,50 +237,9 @@ func (s *ServerConn) kexDH(group *dhGroup, hashFunc crypto.Hash, magics *handsha
return
}
-func serializeRSASignature(sig []byte) []byte {
- length := stringLength([]byte(hostAlgoRSA))
- length += stringLength(sig)
-
- ret := make([]byte, length)
- r := marshalString(ret, []byte(hostAlgoRSA))
- r = marshalString(r, sig)
-
- return ret
-}
-
// serverVersion is the fixed identification string that Server will use.
var serverVersion = []byte("SSH-2.0-Go\r\n")
-// buildDataSignedForAuth returns the data that is signed in order to prove
-// posession of a private key. See RFC 4252, section 7.
-func buildDataSignedForAuth(sessionId []byte, req userAuthRequestMsg, algo, pubKey []byte) []byte {
- user := []byte(req.User)
- service := []byte(req.Service)
- method := []byte(req.Method)
-
- length := stringLength(sessionId)
- length += 1
- length += stringLength(user)
- length += stringLength(service)
- length += stringLength(method)
- length += 1
- length += stringLength(algo)
- length += stringLength(pubKey)
-
- ret := make([]byte, length)
- r := marshalString(ret, sessionId)
- r[0] = msgUserAuthRequest
- r = r[1:]
- r = marshalString(r, user)
- r = marshalString(r, service)
- r = marshalString(r, method)
- r[0] = 1
- r = r[1:]
- r = marshalString(r, algo)
- r = marshalString(r, pubKey)
- return ret
-}
-
// Handshake performs an SSH transport and client authentication on the given ServerConn.
func (s *ServerConn) Handshake() error {
var magics handshakeMagics
@@ -298,8 +260,8 @@ func (s *ServerConn) Handshake() error {
serverKexInit := kexInitMsg{
KexAlgos: supportedKexAlgos,
ServerHostKeyAlgos: supportedHostKeyAlgos,
- CiphersClientServer: supportedCiphers,
- CiphersServerClient: supportedCiphers,
+ CiphersClientServer: s.config.Crypto.ciphers(),
+ CiphersServerClient: s.config.Crypto.ciphers(),
MACsClientServer: supportedMACs,
MACsServerClient: supportedMACs,
CompressionClientServer: supportedCompressions,
@@ -364,7 +326,9 @@ func (s *ServerConn) Handshake() error {
if packet[0] != msgNewKeys {
return UnexpectedMessageError{msgNewKeys, packet[0]}
}
- s.transport.reader.setupKeys(clientKeys, K, H, H, hashFunc)
+ if err = s.transport.reader.setupKeys(clientKeys, K, H, H, hashFunc); err != nil {
+ return err
+ }
if packet, err = s.readPacket(); err != nil {
return err
}
diff --git a/libgo/go/exp/ssh/tcpip.go b/libgo/go/exp/ssh/tcpip.go
new file mode 100644
index 00000000000..859dedc93b3
--- /dev/null
+++ b/libgo/go/exp/ssh/tcpip.go
@@ -0,0 +1,146 @@
+// 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 ssh
+
+import (
+ "errors"
+ "io"
+ "net"
+)
+// Dial initiates a connection to the addr from the remote host.
+// addr is resolved using net.ResolveTCPAddr before connection.
+// This could allow an observer to observe the DNS name of the
+// remote host. Consider using ssh.DialTCP to avoid this.
+func (c *ClientConn) Dial(n, addr string) (net.Conn, error) {
+ raddr, err := net.ResolveTCPAddr(n, addr)
+ if err != nil {
+ return nil, err
+ }
+ return c.DialTCP(n, nil, raddr)
+}
+
+// DialTCP connects to the remote address raddr on the network net,
+// which must be "tcp", "tcp4", or "tcp6". If laddr is not nil, it is used
+// as the local address for the connection.
+func (c *ClientConn) DialTCP(n string, laddr, raddr *net.TCPAddr) (net.Conn, error) {
+ if laddr == nil {
+ laddr = &net.TCPAddr{
+ IP: net.IPv4zero,
+ Port: 0,
+ }
+ }
+ ch, err := c.dial(laddr.IP.String(), laddr.Port, raddr.IP.String(), raddr.Port)
+ if err != nil {
+ return nil, err
+ }
+ return &tcpchanconn{
+ tcpchan: ch,
+ laddr: laddr,
+ raddr: raddr,
+ }, nil
+}
+
+// dial opens a direct-tcpip connection to the remote server. laddr and raddr are passed as
+// strings and are expected to be resolveable at the remote end.
+func (c *ClientConn) dial(laddr string, lport int, raddr string, rport int) (*tcpchan, error) {
+ // RFC 4254 7.2
+ type channelOpenDirectMsg struct {
+ ChanType string
+ PeersId uint32
+ PeersWindow uint32
+ MaxPacketSize uint32
+ raddr string
+ rport uint32
+ laddr string
+ lport uint32
+ }
+ ch := c.newChan(c.transport)
+ if err := c.writePacket(marshal(msgChannelOpen, channelOpenDirectMsg{
+ ChanType: "direct-tcpip",
+ PeersId: ch.id,
+ PeersWindow: 1 << 14,
+ MaxPacketSize: 1 << 15, // RFC 4253 6.1
+ raddr: raddr,
+ rport: uint32(rport),
+ laddr: laddr,
+ lport: uint32(lport),
+ })); err != nil {
+ c.chanlist.remove(ch.id)
+ return nil, err
+ }
+ // wait for response
+ switch msg := (<-ch.msg).(type) {
+ case *channelOpenConfirmMsg:
+ ch.peersId = msg.MyId
+ ch.win <- int(msg.MyWindow)
+ case *channelOpenFailureMsg:
+ c.chanlist.remove(ch.id)
+ return nil, errors.New("ssh: error opening remote TCP connection: " + msg.Message)
+ default:
+ c.chanlist.remove(ch.id)
+ return nil, errors.New("ssh: unexpected packet")
+ }
+ return &tcpchan{
+ clientChan: ch,
+ Reader: &chanReader{
+ packetWriter: ch,
+ id: ch.id,
+ data: ch.data,
+ },
+ Writer: &chanWriter{
+ packetWriter: ch,
+ id: ch.id,
+ win: ch.win,
+ },
+ }, nil
+}
+
+type tcpchan struct {
+ *clientChan // the backing channel
+ io.Reader
+ io.Writer
+}
+
+// tcpchanconn fulfills the net.Conn interface without
+// the tcpchan having to hold laddr or raddr directly.
+type tcpchanconn struct {
+ *tcpchan
+ laddr, raddr net.Addr
+}
+
+// LocalAddr returns the local network address.
+func (t *tcpchanconn) LocalAddr() net.Addr {
+ return t.laddr
+}
+
+// RemoteAddr returns the remote network address.
+func (t *tcpchanconn) RemoteAddr() net.Addr {
+ return t.raddr
+}
+
+// SetTimeout sets the read and write deadlines associated
+// with the connection.
+func (t *tcpchanconn) SetTimeout(nsec int64) error {
+ if err := t.SetReadTimeout(nsec); err != nil {
+ return err
+ }
+ return t.SetWriteTimeout(nsec)
+}
+
+// SetReadTimeout sets the time (in nanoseconds) that
+// Read will wait for data before returning an error with Timeout() == true.
+// Setting nsec == 0 (the default) disables the deadline.
+func (t *tcpchanconn) SetReadTimeout(nsec int64) error {
+ return errors.New("ssh: tcpchan: timeout not supported")
+}
+
+// SetWriteTimeout sets the time (in nanoseconds) that
+// Write will wait to send its data before returning an error with Timeout() == true.
+// Setting nsec == 0 (the default) disables the deadline.
+// Even if write times out, it may return n > 0, indicating that
+// some of the data was successfully written.
+func (t *tcpchanconn) SetWriteTimeout(nsec int64) error {
+ return errors.New("ssh: tcpchan: timeout not supported")
+}
diff --git a/libgo/go/exp/ssh/transport.go b/libgo/go/exp/ssh/transport.go
index 579a9d82de9..b8cb2c319d8 100644
--- a/libgo/go/exp/ssh/transport.go
+++ b/libgo/go/exp/ssh/transport.go
@@ -7,7 +7,6 @@ package ssh
import (
"bufio"
"crypto"
- "crypto/aes"
"crypto/cipher"
"crypto/hmac"
"crypto/subtle"
@@ -19,7 +18,10 @@ import (
)
const (
- paddingMultiple = 16 // TODO(dfc) does this need to be configurable?
+ packetSizeMultiple = 16 // TODO(huin) this should be determined by the cipher.
+ minPacketSize = 16
+ maxPacketSize = 36000
+ minPaddingSize = 4 // TODO(huin) should this be configurable?
)
// filteredConn reduces the set of methods exposed when embeddeding
@@ -61,8 +63,7 @@ type reader struct {
type writer struct {
*sync.Mutex // protects writer.Writer from concurrent writes
*bufio.Writer
- paddingMultiple int
- rand io.Reader
+ rand io.Reader
common
}
@@ -82,14 +83,11 @@ type common struct {
func (r *reader) readOnePacket() ([]byte, error) {
var lengthBytes = make([]byte, 5)
var macSize uint32
-
if _, err := io.ReadFull(r, lengthBytes); err != nil {
return nil, err
}
- if r.cipher != nil {
- r.cipher.XORKeyStream(lengthBytes, lengthBytes)
- }
+ r.cipher.XORKeyStream(lengthBytes, lengthBytes)
if r.mac != nil {
r.mac.Reset()
@@ -153,9 +151,9 @@ func (w *writer) writePacket(packet []byte) error {
w.Mutex.Lock()
defer w.Mutex.Unlock()
- paddingLength := paddingMultiple - (5+len(packet))%paddingMultiple
+ paddingLength := packetSizeMultiple - (5+len(packet))%packetSizeMultiple
if paddingLength < 4 {
- paddingLength += paddingMultiple
+ paddingLength += packetSizeMultiple
}
length := len(packet) + 1 + paddingLength
@@ -188,11 +186,9 @@ func (w *writer) writePacket(packet []byte) error {
// TODO(dfc) lengthBytes, packet and padding should be
// subslices of a single buffer
- if w.cipher != nil {
- w.cipher.XORKeyStream(lengthBytes, lengthBytes)
- w.cipher.XORKeyStream(packet, packet)
- w.cipher.XORKeyStream(padding, padding)
- }
+ w.cipher.XORKeyStream(lengthBytes, lengthBytes)
+ w.cipher.XORKeyStream(packet, packet)
+ w.cipher.XORKeyStream(padding, padding)
if _, err := w.Write(lengthBytes); err != nil {
return err
@@ -227,11 +223,17 @@ func newTransport(conn net.Conn, rand io.Reader) *transport {
return &transport{
reader: reader{
Reader: bufio.NewReader(conn),
+ common: common{
+ cipher: noneCipher{},
+ },
},
writer: writer{
Writer: bufio.NewWriter(conn),
rand: rand,
Mutex: new(sync.Mutex),
+ common: common{
+ cipher: noneCipher{},
+ },
},
filteredConn: conn,
}
@@ -249,29 +251,32 @@ var (
clientKeys = direction{[]byte{'A'}, []byte{'C'}, []byte{'E'}}
)
-// setupKeys sets the cipher and MAC keys from K, H and sessionId, as
+// setupKeys sets the cipher and MAC keys from kex.K, kex.H and sessionId, as
// described in RFC 4253, section 6.4. direction should either be serverKeys
// (to setup server->client keys) or clientKeys (for client->server keys).
func (c *common) setupKeys(d direction, K, H, sessionId []byte, hashFunc crypto.Hash) error {
- h := hashFunc.New()
+ cipherMode := cipherModes[c.cipherAlgo]
- blockSize := 16
- keySize := 16
macKeySize := 20
- iv := make([]byte, blockSize)
- key := make([]byte, keySize)
+ iv := make([]byte, cipherMode.ivSize)
+ key := make([]byte, cipherMode.keySize)
macKey := make([]byte, macKeySize)
+
+ h := hashFunc.New()
generateKeyMaterial(iv, d.ivTag, K, H, sessionId, h)
generateKeyMaterial(key, d.keyTag, K, H, sessionId, h)
generateKeyMaterial(macKey, d.macKeyTag, K, H, sessionId, h)
c.mac = truncatingMAC{12, hmac.NewSHA1(macKey)}
- aes, err := aes.NewCipher(key)
+
+ cipher, err := cipherMode.createCipher(key, iv)
if err != nil {
return err
}
- c.cipher = cipher.NewCTR(aes, iv)
+
+ c.cipher = cipher
+
return nil
}
diff --git a/libgo/go/exp/terminal/shell.go b/libgo/go/exp/terminal/shell.go
deleted file mode 100644
index 5c5916755d6..00000000000
--- a/libgo/go/exp/terminal/shell.go
+++ /dev/null
@@ -1,356 +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 terminal
-
-import "io"
-
-// Shell contains the state for running a VT100 terminal that is capable of
-// reading lines of input.
-type Shell struct {
- c io.ReadWriter
- prompt string
-
- // line is the current line being entered.
- line []byte
- // pos is the logical position of the cursor in line
- pos int
-
- // cursorX contains the current X value of the cursor where the left
- // edge is 0. cursorY contains the row number where the first row of
- // the current line is 0.
- cursorX, cursorY int
- // maxLine is the greatest value of cursorY so far.
- maxLine int
-
- termWidth, termHeight int
-
- // outBuf contains the terminal data to be sent.
- outBuf []byte
- // remainder contains the remainder of any partial key sequences after
- // a read. It aliases into inBuf.
- remainder []byte
- inBuf [256]byte
-}
-
-// NewShell runs a VT100 terminal on the given ReadWriter. If the ReadWriter is
-// a local terminal, that terminal must first have been put into raw mode.
-// prompt is a string that is written at the start of each input line (i.e.
-// "> ").
-func NewShell(c io.ReadWriter, prompt string) *Shell {
- return &Shell{
- c: c,
- prompt: prompt,
- termWidth: 80,
- termHeight: 24,
- }
-}
-
-const (
- keyCtrlD = 4
- keyEnter = '\r'
- keyEscape = 27
- keyBackspace = 127
- keyUnknown = 256 + iota
- keyUp
- keyDown
- keyLeft
- keyRight
- keyAltLeft
- keyAltRight
-)
-
-// bytesToKey tries to parse a key sequence from b. If successful, it returns
-// the key and the remainder of the input. Otherwise it returns -1.
-func bytesToKey(b []byte) (int, []byte) {
- if len(b) == 0 {
- return -1, nil
- }
-
- if b[0] != keyEscape {
- return int(b[0]), b[1:]
- }
-
- if len(b) >= 3 && b[0] == keyEscape && b[1] == '[' {
- switch b[2] {
- case 'A':
- return keyUp, b[3:]
- case 'B':
- return keyDown, b[3:]
- case 'C':
- return keyRight, b[3:]
- case 'D':
- return keyLeft, b[3:]
- }
- }
-
- if len(b) >= 6 && b[0] == keyEscape && b[1] == '[' && b[2] == '1' && b[3] == ';' && b[4] == '3' {
- switch b[5] {
- case 'C':
- return keyAltRight, b[6:]
- case 'D':
- return keyAltLeft, b[6:]
- }
- }
-
- // If we get here then we have a key that we don't recognise, or a
- // partial sequence. It's not clear how one should find the end of a
- // sequence without knowing them all, but it seems that [a-zA-Z] only
- // appears at the end of a sequence.
- for i, c := range b[0:] {
- if c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' {
- return keyUnknown, b[i+1:]
- }
- }
-
- return -1, b
-}
-
-// queue appends data to the end of ss.outBuf
-func (ss *Shell) queue(data []byte) {
- if len(ss.outBuf)+len(data) > cap(ss.outBuf) {
- newOutBuf := make([]byte, len(ss.outBuf), 2*(len(ss.outBuf)+len(data)))
- copy(newOutBuf, ss.outBuf)
- ss.outBuf = newOutBuf
- }
-
- oldLen := len(ss.outBuf)
- ss.outBuf = ss.outBuf[:len(ss.outBuf)+len(data)]
- copy(ss.outBuf[oldLen:], data)
-}
-
-var eraseUnderCursor = []byte{' ', keyEscape, '[', 'D'}
-
-func isPrintable(key int) bool {
- return key >= 32 && key < 127
-}
-
-// moveCursorToPos appends data to ss.outBuf which will move the cursor to the
-// given, logical position in the text.
-func (ss *Shell) moveCursorToPos(pos int) {
- x := len(ss.prompt) + pos
- y := x / ss.termWidth
- x = x % ss.termWidth
-
- up := 0
- if y < ss.cursorY {
- up = ss.cursorY - y
- }
-
- down := 0
- if y > ss.cursorY {
- down = y - ss.cursorY
- }
-
- left := 0
- if x < ss.cursorX {
- left = ss.cursorX - x
- }
-
- right := 0
- if x > ss.cursorX {
- right = x - ss.cursorX
- }
-
- movement := make([]byte, 3*(up+down+left+right))
- m := movement
- for i := 0; i < up; i++ {
- m[0] = keyEscape
- m[1] = '['
- m[2] = 'A'
- m = m[3:]
- }
- for i := 0; i < down; i++ {
- m[0] = keyEscape
- m[1] = '['
- m[2] = 'B'
- m = m[3:]
- }
- for i := 0; i < left; i++ {
- m[0] = keyEscape
- m[1] = '['
- m[2] = 'D'
- m = m[3:]
- }
- for i := 0; i < right; i++ {
- m[0] = keyEscape
- m[1] = '['
- m[2] = 'C'
- m = m[3:]
- }
-
- ss.cursorX = x
- ss.cursorY = y
- ss.queue(movement)
-}
-
-const maxLineLength = 4096
-
-// handleKey processes the given key and, optionally, returns a line of text
-// that the user has entered.
-func (ss *Shell) handleKey(key int) (line string, ok bool) {
- switch key {
- case keyBackspace:
- if ss.pos == 0 {
- return
- }
- ss.pos--
-
- copy(ss.line[ss.pos:], ss.line[1+ss.pos:])
- ss.line = ss.line[:len(ss.line)-1]
- ss.writeLine(ss.line[ss.pos:])
- ss.moveCursorToPos(ss.pos)
- ss.queue(eraseUnderCursor)
- case keyAltLeft:
- // move left by a word.
- if ss.pos == 0 {
- return
- }
- ss.pos--
- for ss.pos > 0 {
- if ss.line[ss.pos] != ' ' {
- break
- }
- ss.pos--
- }
- for ss.pos > 0 {
- if ss.line[ss.pos] == ' ' {
- ss.pos++
- break
- }
- ss.pos--
- }
- ss.moveCursorToPos(ss.pos)
- case keyAltRight:
- // move right by a word.
- for ss.pos < len(ss.line) {
- if ss.line[ss.pos] == ' ' {
- break
- }
- ss.pos++
- }
- for ss.pos < len(ss.line) {
- if ss.line[ss.pos] != ' ' {
- break
- }
- ss.pos++
- }
- ss.moveCursorToPos(ss.pos)
- case keyLeft:
- if ss.pos == 0 {
- return
- }
- ss.pos--
- ss.moveCursorToPos(ss.pos)
- case keyRight:
- if ss.pos == len(ss.line) {
- return
- }
- ss.pos++
- ss.moveCursorToPos(ss.pos)
- case keyEnter:
- ss.moveCursorToPos(len(ss.line))
- ss.queue([]byte("\r\n"))
- line = string(ss.line)
- ok = true
- ss.line = ss.line[:0]
- ss.pos = 0
- ss.cursorX = 0
- ss.cursorY = 0
- ss.maxLine = 0
- default:
- if !isPrintable(key) {
- return
- }
- if len(ss.line) == maxLineLength {
- return
- }
- if len(ss.line) == cap(ss.line) {
- newLine := make([]byte, len(ss.line), 2*(1+len(ss.line)))
- copy(newLine, ss.line)
- ss.line = newLine
- }
- ss.line = ss.line[:len(ss.line)+1]
- copy(ss.line[ss.pos+1:], ss.line[ss.pos:])
- ss.line[ss.pos] = byte(key)
- ss.writeLine(ss.line[ss.pos:])
- ss.pos++
- ss.moveCursorToPos(ss.pos)
- }
- return
-}
-
-func (ss *Shell) writeLine(line []byte) {
- for len(line) != 0 {
- if ss.cursorX == ss.termWidth {
- ss.queue([]byte("\r\n"))
- ss.cursorX = 0
- ss.cursorY++
- if ss.cursorY > ss.maxLine {
- ss.maxLine = ss.cursorY
- }
- }
-
- remainingOnLine := ss.termWidth - ss.cursorX
- todo := len(line)
- if todo > remainingOnLine {
- todo = remainingOnLine
- }
- ss.queue(line[:todo])
- ss.cursorX += todo
- line = line[todo:]
- }
-}
-
-func (ss *Shell) Write(buf []byte) (n int, err error) {
- return ss.c.Write(buf)
-}
-
-// ReadLine returns a line of input from the terminal.
-func (ss *Shell) ReadLine() (line string, err error) {
- ss.writeLine([]byte(ss.prompt))
- ss.c.Write(ss.outBuf)
- ss.outBuf = ss.outBuf[:0]
-
- for {
- // ss.remainder is a slice at the beginning of ss.inBuf
- // containing a partial key sequence
- readBuf := ss.inBuf[len(ss.remainder):]
- var n int
- n, err = ss.c.Read(readBuf)
- if err != nil {
- return
- }
-
- if err == nil {
- ss.remainder = ss.inBuf[:n+len(ss.remainder)]
- rest := ss.remainder
- lineOk := false
- for !lineOk {
- var key int
- key, rest = bytesToKey(rest)
- if key < 0 {
- break
- }
- if key == keyCtrlD {
- return "", io.EOF
- }
- line, lineOk = ss.handleKey(key)
- }
- if len(rest) > 0 {
- n := copy(ss.inBuf[:], rest)
- ss.remainder = ss.inBuf[:n]
- } else {
- ss.remainder = nil
- }
- ss.c.Write(ss.outBuf)
- ss.outBuf = ss.outBuf[:0]
- if lineOk {
- return
- }
- continue
- }
- }
- panic("unreachable")
-}
diff --git a/libgo/go/exp/terminal/terminal.go b/libgo/go/exp/terminal/terminal.go
index 5732543ffc2..18d76cd6b90 100644
--- a/libgo/go/exp/terminal/terminal.go
+++ b/libgo/go/exp/terminal/terminal.go
@@ -2,102 +2,361 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package terminal provides support functions for dealing with terminals, as
-// commonly found on UNIX systems.
-//
-// Putting a terminal into raw mode is the most common requirement:
-//
-// oldState, err := terminal.MakeRaw(0)
-// if err != nil {
-// panic(err.String())
-// }
-// defer terminal.Restore(0, oldState)
package terminal
-import (
- "io"
- "os"
- "syscall"
-)
+import "io"
+
+// Terminal contains the state for running a VT100 terminal that is capable of
+// reading lines of input.
+type Terminal struct {
+ c io.ReadWriter
+ prompt string
+
+ // line is the current line being entered.
+ line []byte
+ // pos is the logical position of the cursor in line
+ pos int
+
+ // cursorX contains the current X value of the cursor where the left
+ // edge is 0. cursorY contains the row number where the first row of
+ // the current line is 0.
+ cursorX, cursorY int
+ // maxLine is the greatest value of cursorY so far.
+ maxLine int
+
+ termWidth, termHeight int
-// State contains the state of a terminal.
-type State struct {
- termios syscall.Termios
+ // outBuf contains the terminal data to be sent.
+ outBuf []byte
+ // remainder contains the remainder of any partial key sequences after
+ // a read. It aliases into inBuf.
+ remainder []byte
+ inBuf [256]byte
}
-// IsTerminal returns true if the given file descriptor is a terminal.
-func IsTerminal(fd int) bool {
- var termios syscall.Termios
- e := syscall.Tcgetattr(fd, &termios)
- return e == 0
+// NewTerminal runs a VT100 terminal on the given ReadWriter. If the ReadWriter is
+// a local terminal, that terminal must first have been put into raw mode.
+// prompt is a string that is written at the start of each input line (i.e.
+// "> ").
+func NewTerminal(c io.ReadWriter, prompt string) *Terminal {
+ return &Terminal{
+ c: c,
+ prompt: prompt,
+ termWidth: 80,
+ termHeight: 24,
+ }
}
-// MakeRaw put the terminal connected to the given file descriptor into raw
-// mode and returns the previous state of the terminal so that it can be
-// restored.
-func MakeRaw(fd int) (*State, error) {
- var oldState State
- if e := syscall.Tcgetattr(fd, &oldState.termios); e != 0 {
- return nil, os.Errno(e)
+const (
+ keyCtrlD = 4
+ keyEnter = '\r'
+ keyEscape = 27
+ keyBackspace = 127
+ keyUnknown = 256 + iota
+ keyUp
+ keyDown
+ keyLeft
+ keyRight
+ keyAltLeft
+ keyAltRight
+)
+
+// bytesToKey tries to parse a key sequence from b. If successful, it returns
+// the key and the remainder of the input. Otherwise it returns -1.
+func bytesToKey(b []byte) (int, []byte) {
+ if len(b) == 0 {
+ return -1, nil
+ }
+
+ if b[0] != keyEscape {
+ return int(b[0]), b[1:]
+ }
+
+ if len(b) >= 3 && b[0] == keyEscape && b[1] == '[' {
+ switch b[2] {
+ case 'A':
+ return keyUp, b[3:]
+ case 'B':
+ return keyDown, b[3:]
+ case 'C':
+ return keyRight, b[3:]
+ case 'D':
+ return keyLeft, b[3:]
+ }
+ }
+
+ if len(b) >= 6 && b[0] == keyEscape && b[1] == '[' && b[2] == '1' && b[3] == ';' && b[4] == '3' {
+ switch b[5] {
+ case 'C':
+ return keyAltRight, b[6:]
+ case 'D':
+ return keyAltLeft, b[6:]
+ }
+ }
+
+ // If we get here then we have a key that we don't recognise, or a
+ // partial sequence. It's not clear how one should find the end of a
+ // sequence without knowing them all, but it seems that [a-zA-Z] only
+ // appears at the end of a sequence.
+ for i, c := range b[0:] {
+ if c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' {
+ return keyUnknown, b[i+1:]
+ }
}
- newState := oldState.termios
- newState.Iflag &^= syscall.ISTRIP | syscall.INLCR | syscall.ICRNL | syscall.IGNCR | syscall.IXON | syscall.IXOFF
- newState.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.ISIG
- if e := syscall.Tcsetattr(fd, syscall.TCSANOW, &newState); e != 0 {
- return nil, os.Errno(e)
+ return -1, b
+}
+
+// queue appends data to the end of t.outBuf
+func (t *Terminal) queue(data []byte) {
+ if len(t.outBuf)+len(data) > cap(t.outBuf) {
+ newOutBuf := make([]byte, len(t.outBuf), 2*(len(t.outBuf)+len(data)))
+ copy(newOutBuf, t.outBuf)
+ t.outBuf = newOutBuf
}
- return &oldState, nil
+ oldLen := len(t.outBuf)
+ t.outBuf = t.outBuf[:len(t.outBuf)+len(data)]
+ copy(t.outBuf[oldLen:], data)
}
-// Restore restores the terminal connected to the given file descriptor to a
-// previous state.
-func Restore(fd int, state *State) error {
- e := syscall.Tcsetattr(fd, syscall.TCSANOW, &state.termios)
- return os.Errno(e)
+var eraseUnderCursor = []byte{' ', keyEscape, '[', 'D'}
+
+func isPrintable(key int) bool {
+ return key >= 32 && key < 127
}
-// ReadPassword reads a line of input from a terminal without local echo. This
-// is commonly used for inputting passwords and other sensitive data. The slice
-// returned does not include the \n.
-func ReadPassword(fd int) ([]byte, error) {
- var oldState syscall.Termios
- if e := syscall.Tcgetattr(fd, &oldState); e != 0 {
- return nil, os.Errno(e)
+// moveCursorToPos appends data to t.outBuf which will move the cursor to the
+// given, logical position in the text.
+func (t *Terminal) moveCursorToPos(pos int) {
+ x := len(t.prompt) + pos
+ y := x / t.termWidth
+ x = x % t.termWidth
+
+ up := 0
+ if y < t.cursorY {
+ up = t.cursorY - y
}
- newState := oldState
- newState.Lflag &^= syscall.ECHO
- if e := syscall.Tcsetattr(fd, syscall.TCSANOW, &newState); e != 0 {
- return nil, os.Errno(e)
+ down := 0
+ if y > t.cursorY {
+ down = y - t.cursorY
}
- defer func() {
- syscall.Tcsetattr(fd, syscall.TCSANOW, &oldState)
- }()
+ left := 0
+ if x < t.cursorX {
+ left = t.cursorX - x
+ }
- var buf [16]byte
- var ret []byte
- for {
- n, errno := syscall.Read(fd, buf[:])
- if errno != 0 {
- return nil, os.Errno(errno)
+ right := 0
+ if x > t.cursorX {
+ right = x - t.cursorX
+ }
+
+ movement := make([]byte, 3*(up+down+left+right))
+ m := movement
+ for i := 0; i < up; i++ {
+ m[0] = keyEscape
+ m[1] = '['
+ m[2] = 'A'
+ m = m[3:]
+ }
+ for i := 0; i < down; i++ {
+ m[0] = keyEscape
+ m[1] = '['
+ m[2] = 'B'
+ m = m[3:]
+ }
+ for i := 0; i < left; i++ {
+ m[0] = keyEscape
+ m[1] = '['
+ m[2] = 'D'
+ m = m[3:]
+ }
+ for i := 0; i < right; i++ {
+ m[0] = keyEscape
+ m[1] = '['
+ m[2] = 'C'
+ m = m[3:]
+ }
+
+ t.cursorX = x
+ t.cursorY = y
+ t.queue(movement)
+}
+
+const maxLineLength = 4096
+
+// handleKey processes the given key and, optionally, returns a line of text
+// that the user has entered.
+func (t *Terminal) handleKey(key int) (line string, ok bool) {
+ switch key {
+ case keyBackspace:
+ if t.pos == 0 {
+ return
+ }
+ t.pos--
+
+ copy(t.line[t.pos:], t.line[1+t.pos:])
+ t.line = t.line[:len(t.line)-1]
+ t.writeLine(t.line[t.pos:])
+ t.moveCursorToPos(t.pos)
+ t.queue(eraseUnderCursor)
+ case keyAltLeft:
+ // move left by a word.
+ if t.pos == 0 {
+ return
+ }
+ t.pos--
+ for t.pos > 0 {
+ if t.line[t.pos] != ' ' {
+ break
+ }
+ t.pos--
+ }
+ for t.pos > 0 {
+ if t.line[t.pos] == ' ' {
+ t.pos++
+ break
+ }
+ t.pos--
+ }
+ t.moveCursorToPos(t.pos)
+ case keyAltRight:
+ // move right by a word.
+ for t.pos < len(t.line) {
+ if t.line[t.pos] == ' ' {
+ break
+ }
+ t.pos++
}
- if n == 0 {
- if len(ret) == 0 {
- return nil, io.EOF
+ for t.pos < len(t.line) {
+ if t.line[t.pos] != ' ' {
+ break
+ }
+ t.pos++
+ }
+ t.moveCursorToPos(t.pos)
+ case keyLeft:
+ if t.pos == 0 {
+ return
+ }
+ t.pos--
+ t.moveCursorToPos(t.pos)
+ case keyRight:
+ if t.pos == len(t.line) {
+ return
+ }
+ t.pos++
+ t.moveCursorToPos(t.pos)
+ case keyEnter:
+ t.moveCursorToPos(len(t.line))
+ t.queue([]byte("\r\n"))
+ line = string(t.line)
+ ok = true
+ t.line = t.line[:0]
+ t.pos = 0
+ t.cursorX = 0
+ t.cursorY = 0
+ t.maxLine = 0
+ default:
+ if !isPrintable(key) {
+ return
+ }
+ if len(t.line) == maxLineLength {
+ return
+ }
+ if len(t.line) == cap(t.line) {
+ newLine := make([]byte, len(t.line), 2*(1+len(t.line)))
+ copy(newLine, t.line)
+ t.line = newLine
+ }
+ t.line = t.line[:len(t.line)+1]
+ copy(t.line[t.pos+1:], t.line[t.pos:])
+ t.line[t.pos] = byte(key)
+ t.writeLine(t.line[t.pos:])
+ t.pos++
+ t.moveCursorToPos(t.pos)
+ }
+ return
+}
+
+func (t *Terminal) writeLine(line []byte) {
+ for len(line) != 0 {
+ if t.cursorX == t.termWidth {
+ t.queue([]byte("\r\n"))
+ t.cursorX = 0
+ t.cursorY++
+ if t.cursorY > t.maxLine {
+ t.maxLine = t.cursorY
}
- break
}
- if buf[n-1] == '\n' {
- n--
+
+ remainingOnLine := t.termWidth - t.cursorX
+ todo := len(line)
+ if todo > remainingOnLine {
+ todo = remainingOnLine
}
- ret = append(ret, buf[:n]...)
- if n < len(buf) {
- break
+ t.queue(line[:todo])
+ t.cursorX += todo
+ line = line[todo:]
+ }
+}
+
+func (t *Terminal) Write(buf []byte) (n int, err error) {
+ return t.c.Write(buf)
+}
+
+// ReadLine returns a line of input from the terminal.
+func (t *Terminal) ReadLine() (line string, err error) {
+ if t.cursorX == 0 {
+ t.writeLine([]byte(t.prompt))
+ t.c.Write(t.outBuf)
+ t.outBuf = t.outBuf[:0]
+ }
+
+ for {
+ // t.remainder is a slice at the beginning of t.inBuf
+ // containing a partial key sequence
+ readBuf := t.inBuf[len(t.remainder):]
+ var n int
+ n, err = t.c.Read(readBuf)
+ if err != nil {
+ return
+ }
+
+ if err == nil {
+ t.remainder = t.inBuf[:n+len(t.remainder)]
+ rest := t.remainder
+ lineOk := false
+ for !lineOk {
+ var key int
+ key, rest = bytesToKey(rest)
+ if key < 0 {
+ break
+ }
+ if key == keyCtrlD {
+ return "", io.EOF
+ }
+ line, lineOk = t.handleKey(key)
+ }
+ if len(rest) > 0 {
+ n := copy(t.inBuf[:], rest)
+ t.remainder = t.inBuf[:n]
+ } else {
+ t.remainder = nil
+ }
+ t.c.Write(t.outBuf)
+ t.outBuf = t.outBuf[:0]
+ if lineOk {
+ return
+ }
+ continue
}
}
+ panic("unreachable")
+}
- return ret, nil
+func (t *Terminal) SetSize(width, height int) {
+ t.termWidth, t.termHeight = width, height
}
diff --git a/libgo/go/exp/terminal/shell_test.go b/libgo/go/exp/terminal/terminal_test.go
index 8a76a85d5dc..a2197210e2a 100644
--- a/libgo/go/exp/terminal/shell_test.go
+++ b/libgo/go/exp/terminal/terminal_test.go
@@ -41,7 +41,7 @@ func (c *MockTerminal) Write(data []byte) (n int, err error) {
func TestClose(t *testing.T) {
c := &MockTerminal{}
- ss := NewShell(c, "> ")
+ ss := NewTerminal(c, "> ")
line, err := ss.ReadLine()
if line != "" {
t.Errorf("Expected empty line but got: %s", line)
@@ -95,7 +95,7 @@ func TestKeyPresses(t *testing.T) {
toSend: []byte(test.in),
bytesPerRead: j,
}
- ss := NewShell(c, "> ")
+ ss := NewTerminal(c, "> ")
line, err := ss.ReadLine()
if line != test.line {
t.Errorf("Line resulting from test %d (%d bytes per read) was '%s', expected '%s'", i, j, line, test.line)
diff --git a/libgo/go/exp/terminal/util.go b/libgo/go/exp/terminal/util.go
new file mode 100644
index 00000000000..03035673869
--- /dev/null
+++ b/libgo/go/exp/terminal/util.go
@@ -0,0 +1,102 @@
+// 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 terminal provides support functions for dealing with terminals, as
+// commonly found on UNIX systems.
+//
+// Putting a terminal into raw mode is the most common requirement:
+//
+// oldState, err := terminal.MakeRaw(0)
+// if err != nil {
+// panic(err.String())
+// }
+// defer terminal.Restore(0, oldState)
+package terminal
+
+import (
+ "io"
+ "syscall"
+)
+
+// State contains the state of a terminal.
+type State struct {
+ termios syscall.Termios
+}
+
+// IsTerminal returns true if the given file descriptor is a terminal.
+func IsTerminal(fd int) bool {
+ var termios syscall.Termios
+ err := syscall.Tcgetattr(fd, &termios)
+ return err == nil
+}
+
+// MakeRaw put the terminal connected to the given file descriptor into raw
+// mode and returns the previous state of the terminal so that it can be
+// restored.
+func MakeRaw(fd int) (*State, error) {
+ var oldState State
+ if err := syscall.Tcgetattr(fd, &oldState.termios); err != nil {
+ return nil, err
+ }
+
+ newState := oldState.termios
+ newState.Iflag &^= syscall.ISTRIP | syscall.INLCR | syscall.ICRNL | syscall.IGNCR | syscall.IXON | syscall.IXOFF
+ newState.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.ISIG
+ if err := syscall.Tcsetattr(fd, syscall.TCSANOW, &newState); err != nil {
+ return nil, err
+ }
+
+ return &oldState, nil
+}
+
+// Restore restores the terminal connected to the given file descriptor to a
+// previous state.
+func Restore(fd int, state *State) error {
+ err := syscall.Tcsetattr(fd, syscall.TCSANOW, &state.termios)
+ return err
+}
+
+// ReadPassword reads a line of input from a terminal without local echo. This
+// is commonly used for inputting passwords and other sensitive data. The slice
+// returned does not include the \n.
+func ReadPassword(fd int) ([]byte, error) {
+ var oldState syscall.Termios
+ if err := syscall.Tcgetattr(fd, &oldState); err != nil {
+ return nil, err
+ }
+
+ newState := oldState
+ newState.Lflag &^= syscall.ECHO
+ if err := syscall.Tcsetattr(fd, syscall.TCSANOW, &newState); err != nil {
+ return nil, err
+ }
+
+ defer func() {
+ syscall.Tcsetattr(fd, syscall.TCSANOW, &oldState)
+ }()
+
+ var buf [16]byte
+ var ret []byte
+ for {
+ n, err := syscall.Read(fd, buf[:])
+ if err != nil {
+ return nil, err
+ }
+ if n == 0 {
+ if len(ret) == 0 {
+ return nil, io.EOF
+ }
+ break
+ }
+ if buf[n-1] == '\n' {
+ n--
+ }
+ ret = append(ret, buf[:n]...)
+ if n < len(buf) {
+ break
+ }
+ }
+
+ return ret, nil
+}
diff --git a/libgo/go/fmt/fmt_test.go b/libgo/go/fmt/fmt_test.go
index db83f85f957..6370560d0bf 100644
--- a/libgo/go/fmt/fmt_test.go
+++ b/libgo/go/fmt/fmt_test.go
@@ -357,6 +357,10 @@ var fmttests = []struct {
{"%#v", map[string]B{"a": {1, 2}}, `map[string] fmt_test.B{"a":fmt_test.B{I:1, j:2}}`},
{"%#v", []string{"a", "b"}, `[]string{"a", "b"}`},
{"%#v", SI{}, `fmt_test.SI{I:interface {}(nil)}`},
+ {"%#v", []int(nil), `[]int(nil)`},
+ {"%#v", []int{}, `[]int{}`},
+ {"%#v", map[int]byte(nil), `map[int] uint8(nil)`},
+ {"%#v", map[int]byte{}, `map[int] uint8{}`},
// slices with other formats
{"%#x", []int{1, 2, 15}, `[0x1 0x2 0xf]`},
diff --git a/libgo/go/fmt/print.go b/libgo/go/fmt/print.go
index bfa88d18704..7143e07a36e 100644
--- a/libgo/go/fmt/print.go
+++ b/libgo/go/fmt/print.go
@@ -795,6 +795,10 @@ BigSwitch:
case reflect.Map:
if goSyntax {
p.buf.WriteString(f.Type().String())
+ if f.IsNil() {
+ p.buf.WriteString("(nil)")
+ break
+ }
p.buf.WriteByte('{')
} else {
p.buf.Write(mapBytes)
@@ -873,6 +877,10 @@ BigSwitch:
}
if goSyntax {
p.buf.WriteString(value.Type().String())
+ if f.IsNil() {
+ p.buf.WriteString("(nil)")
+ break
+ }
p.buf.WriteByte('{')
} else {
p.buf.WriteByte('[')
diff --git a/libgo/go/fmt/scan_test.go b/libgo/go/fmt/scan_test.go
index d3c39be6071..0689bf3b6e4 100644
--- a/libgo/go/fmt/scan_test.go
+++ b/libgo/go/fmt/scan_test.go
@@ -324,7 +324,7 @@ var x, y Xs
var z IntString
var multiTests = []ScanfMultiTest{
- {"", "", nil, nil, ""},
+ {"", "", []interface{}{}, []interface{}{}, ""},
{"%d", "23", args(&i), args(23), ""},
{"%2s%3s", "22333", args(&s, &t), args("22", "333"), ""},
{"%2d%3d", "44555", args(&i, &j), args(44, 555), ""},
@@ -378,7 +378,7 @@ func testScan(name string, t *testing.T, scan func(r io.Reader, a ...interface{}
}
val := v.Interface()
if !reflect.DeepEqual(val, test.out) {
- t.Errorf("%s scanning %q: expected %v got %v, type %T", name, test.text, test.out, val, val)
+ t.Errorf("%s scanning %q: expected %#v got %#v, type %T", name, test.text, test.out, val, val)
}
}
}
@@ -417,7 +417,7 @@ func TestScanf(t *testing.T) {
}
val := v.Interface()
if !reflect.DeepEqual(val, test.out) {
- t.Errorf("scanning (%q, %q): expected %v got %v, type %T", test.format, test.text, test.out, val, val)
+ t.Errorf("scanning (%q, %q): expected %#v got %#v, type %T", test.format, test.text, test.out, val, val)
}
}
}
@@ -520,7 +520,7 @@ func testScanfMulti(name string, t *testing.T) {
}
result := resultVal.Interface()
if !reflect.DeepEqual(result, test.out) {
- t.Errorf("scanning (%q, %q): expected %v got %v", test.format, test.text, test.out, result)
+ t.Errorf("scanning (%q, %q): expected %#v got %#v", test.format, test.text, test.out, result)
}
}
}
diff --git a/libgo/go/go/ast/ast.go b/libgo/go/go/ast/ast.go
index a0aa5ff1204..1485f351c07 100644
--- a/libgo/go/go/ast/ast.go
+++ b/libgo/go/go/ast/ast.go
@@ -412,29 +412,29 @@ func (x *ChanType) End() token.Pos { return x.Value.End() }
// exprNode() ensures that only expression/type nodes can be
// assigned to an ExprNode.
//
-func (x *BadExpr) exprNode() {}
-func (x *Ident) exprNode() {}
-func (x *Ellipsis) exprNode() {}
-func (x *BasicLit) exprNode() {}
-func (x *FuncLit) exprNode() {}
-func (x *CompositeLit) exprNode() {}
-func (x *ParenExpr) exprNode() {}
-func (x *SelectorExpr) exprNode() {}
-func (x *IndexExpr) exprNode() {}
-func (x *SliceExpr) exprNode() {}
-func (x *TypeAssertExpr) exprNode() {}
-func (x *CallExpr) exprNode() {}
-func (x *StarExpr) exprNode() {}
-func (x *UnaryExpr) exprNode() {}
-func (x *BinaryExpr) exprNode() {}
-func (x *KeyValueExpr) exprNode() {}
-
-func (x *ArrayType) exprNode() {}
-func (x *StructType) exprNode() {}
-func (x *FuncType) exprNode() {}
-func (x *InterfaceType) exprNode() {}
-func (x *MapType) exprNode() {}
-func (x *ChanType) exprNode() {}
+func (*BadExpr) exprNode() {}
+func (*Ident) exprNode() {}
+func (*Ellipsis) exprNode() {}
+func (*BasicLit) exprNode() {}
+func (*FuncLit) exprNode() {}
+func (*CompositeLit) exprNode() {}
+func (*ParenExpr) exprNode() {}
+func (*SelectorExpr) exprNode() {}
+func (*IndexExpr) exprNode() {}
+func (*SliceExpr) exprNode() {}
+func (*TypeAssertExpr) exprNode() {}
+func (*CallExpr) exprNode() {}
+func (*StarExpr) exprNode() {}
+func (*UnaryExpr) exprNode() {}
+func (*BinaryExpr) exprNode() {}
+func (*KeyValueExpr) exprNode() {}
+
+func (*ArrayType) exprNode() {}
+func (*StructType) exprNode() {}
+func (*FuncType) exprNode() {}
+func (*InterfaceType) exprNode() {}
+func (*MapType) exprNode() {}
+func (*ChanType) exprNode() {}
// ----------------------------------------------------------------------------
// Convenience functions for Idents
@@ -711,27 +711,27 @@ func (s *RangeStmt) End() token.Pos { return s.Body.End() }
// stmtNode() ensures that only statement nodes can be
// assigned to a StmtNode.
//
-func (s *BadStmt) stmtNode() {}
-func (s *DeclStmt) stmtNode() {}
-func (s *EmptyStmt) stmtNode() {}
-func (s *LabeledStmt) stmtNode() {}
-func (s *ExprStmt) stmtNode() {}
-func (s *SendStmt) stmtNode() {}
-func (s *IncDecStmt) stmtNode() {}
-func (s *AssignStmt) stmtNode() {}
-func (s *GoStmt) stmtNode() {}
-func (s *DeferStmt) stmtNode() {}
-func (s *ReturnStmt) stmtNode() {}
-func (s *BranchStmt) stmtNode() {}
-func (s *BlockStmt) stmtNode() {}
-func (s *IfStmt) stmtNode() {}
-func (s *CaseClause) stmtNode() {}
-func (s *SwitchStmt) stmtNode() {}
-func (s *TypeSwitchStmt) stmtNode() {}
-func (s *CommClause) stmtNode() {}
-func (s *SelectStmt) stmtNode() {}
-func (s *ForStmt) stmtNode() {}
-func (s *RangeStmt) stmtNode() {}
+func (*BadStmt) stmtNode() {}
+func (*DeclStmt) stmtNode() {}
+func (*EmptyStmt) stmtNode() {}
+func (*LabeledStmt) stmtNode() {}
+func (*ExprStmt) stmtNode() {}
+func (*SendStmt) stmtNode() {}
+func (*IncDecStmt) stmtNode() {}
+func (*AssignStmt) stmtNode() {}
+func (*GoStmt) stmtNode() {}
+func (*DeferStmt) stmtNode() {}
+func (*ReturnStmt) stmtNode() {}
+func (*BranchStmt) stmtNode() {}
+func (*BlockStmt) stmtNode() {}
+func (*IfStmt) stmtNode() {}
+func (*CaseClause) stmtNode() {}
+func (*SwitchStmt) stmtNode() {}
+func (*TypeSwitchStmt) stmtNode() {}
+func (*CommClause) stmtNode() {}
+func (*SelectStmt) stmtNode() {}
+func (*ForStmt) stmtNode() {}
+func (*RangeStmt) stmtNode() {}
// ----------------------------------------------------------------------------
// Declarations
@@ -807,9 +807,9 @@ func (s *TypeSpec) End() token.Pos { return s.Type.End() }
// specNode() ensures that only spec nodes can be
// assigned to a Spec.
//
-func (s *ImportSpec) specNode() {}
-func (s *ValueSpec) specNode() {}
-func (s *TypeSpec) specNode() {}
+func (*ImportSpec) specNode() {}
+func (*ValueSpec) specNode() {}
+func (*TypeSpec) specNode() {}
// A declaration is represented by one of the following declaration nodes.
//
@@ -875,9 +875,9 @@ func (d *FuncDecl) End() token.Pos {
// declNode() ensures that only declaration nodes can be
// assigned to a DeclNode.
//
-func (d *BadDecl) declNode() {}
-func (d *GenDecl) declNode() {}
-func (d *FuncDecl) declNode() {}
+func (*BadDecl) declNode() {}
+func (*GenDecl) declNode() {}
+func (*FuncDecl) declNode() {}
// ----------------------------------------------------------------------------
// Files and packages
diff --git a/libgo/go/go/ast/filter.go b/libgo/go/go/ast/filter.go
index d7d4b4b6b6d..bec235e2f98 100644
--- a/libgo/go/go/ast/filter.go
+++ b/libgo/go/go/ast/filter.go
@@ -24,7 +24,7 @@ func exportFilter(name string) bool {
// it returns false otherwise.
//
func FileExports(src *File) bool {
- return FilterFile(src, exportFilter)
+ return filterFile(src, exportFilter, true)
}
// PackageExports trims the AST for a Go package in place such that
@@ -35,7 +35,7 @@ func FileExports(src *File) bool {
// it returns false otherwise.
//
func PackageExports(pkg *Package) bool {
- return FilterPackage(pkg, exportFilter)
+ return filterPackage(pkg, exportFilter, true)
}
// ----------------------------------------------------------------------------
@@ -72,7 +72,7 @@ func fieldName(x Expr) *Ident {
return nil
}
-func filterFieldList(fields *FieldList, filter Filter) (removedFields bool) {
+func filterFieldList(fields *FieldList, filter Filter, export bool) (removedFields bool) {
if fields == nil {
return false
}
@@ -93,8 +93,8 @@ func filterFieldList(fields *FieldList, filter Filter) (removedFields bool) {
keepField = len(f.Names) > 0
}
if keepField {
- if filter == exportFilter {
- filterType(f.Type, filter)
+ if export {
+ filterType(f.Type, filter, export)
}
list[j] = f
j++
@@ -107,84 +107,84 @@ func filterFieldList(fields *FieldList, filter Filter) (removedFields bool) {
return
}
-func filterParamList(fields *FieldList, filter Filter) bool {
+func filterParamList(fields *FieldList, filter Filter, export bool) bool {
if fields == nil {
return false
}
var b bool
for _, f := range fields.List {
- if filterType(f.Type, filter) {
+ if filterType(f.Type, filter, export) {
b = true
}
}
return b
}
-func filterType(typ Expr, f Filter) bool {
+func filterType(typ Expr, f Filter, export bool) bool {
switch t := typ.(type) {
case *Ident:
return f(t.Name)
case *ParenExpr:
- return filterType(t.X, f)
+ return filterType(t.X, f, export)
case *ArrayType:
- return filterType(t.Elt, f)
+ return filterType(t.Elt, f, export)
case *StructType:
- if filterFieldList(t.Fields, f) {
+ if filterFieldList(t.Fields, f, export) {
t.Incomplete = true
}
return len(t.Fields.List) > 0
case *FuncType:
- b1 := filterParamList(t.Params, f)
- b2 := filterParamList(t.Results, f)
+ b1 := filterParamList(t.Params, f, export)
+ b2 := filterParamList(t.Results, f, export)
return b1 || b2
case *InterfaceType:
- if filterFieldList(t.Methods, f) {
+ if filterFieldList(t.Methods, f, export) {
t.Incomplete = true
}
return len(t.Methods.List) > 0
case *MapType:
- b1 := filterType(t.Key, f)
- b2 := filterType(t.Value, f)
+ b1 := filterType(t.Key, f, export)
+ b2 := filterType(t.Value, f, export)
return b1 || b2
case *ChanType:
- return filterType(t.Value, f)
+ return filterType(t.Value, f, export)
}
return false
}
-func filterSpec(spec Spec, f Filter) bool {
+func filterSpec(spec Spec, f Filter, export bool) bool {
switch s := spec.(type) {
case *ValueSpec:
s.Names = filterIdentList(s.Names, f)
if len(s.Names) > 0 {
- if f == exportFilter {
- filterType(s.Type, f)
+ if export {
+ filterType(s.Type, f, export)
}
return true
}
case *TypeSpec:
if f(s.Name.Name) {
- if f == exportFilter {
- filterType(s.Type, f)
+ if export {
+ filterType(s.Type, f, export)
}
return true
}
- if f != exportFilter {
+ if !export {
// For general filtering (not just exports),
// filter type even if name is not filtered
// out.
// If the type contains filtered elements,
// keep the declaration.
- return filterType(s.Type, f)
+ return filterType(s.Type, f, export)
}
}
return false
}
-func filterSpecList(list []Spec, f Filter) []Spec {
+func filterSpecList(list []Spec, f Filter, export bool) []Spec {
j := 0
for _, s := range list {
- if filterSpec(s, f) {
+ if filterSpec(s, f, export) {
list[j] = s
j++
}
@@ -200,9 +200,13 @@ func filterSpecList(list []Spec, f Filter) []Spec {
// filtering; it returns false otherwise.
//
func FilterDecl(decl Decl, f Filter) bool {
+ return filterDecl(decl, f, false)
+}
+
+func filterDecl(decl Decl, f Filter, export bool) bool {
switch d := decl.(type) {
case *GenDecl:
- d.Specs = filterSpecList(d.Specs, f)
+ d.Specs = filterSpecList(d.Specs, f, export)
return len(d.Specs) > 0
case *FuncDecl:
return f(d.Name.Name)
@@ -221,9 +225,13 @@ func FilterDecl(decl Decl, f Filter) bool {
// left after filtering; it returns false otherwise.
//
func FilterFile(src *File, f Filter) bool {
+ return filterFile(src, f, false)
+}
+
+func filterFile(src *File, f Filter, export bool) bool {
j := 0
for _, d := range src.Decls {
- if FilterDecl(d, f) {
+ if filterDecl(d, f, export) {
src.Decls[j] = d
j++
}
@@ -244,9 +252,13 @@ func FilterFile(src *File, f Filter) bool {
// left after filtering; it returns false otherwise.
//
func FilterPackage(pkg *Package, f Filter) bool {
+ return filterPackage(pkg, f, false)
+}
+
+func filterPackage(pkg *Package, f Filter, export bool) bool {
hasDecls := false
for _, src := range pkg.Files {
- if FilterFile(src, f) {
+ if filterFile(src, f, export) {
hasDecls = true
}
}
diff --git a/libgo/go/go/build/build_test.go b/libgo/go/go/build/build_test.go
index db8bc6c8a59..e22a49aa3d6 100644
--- a/libgo/go/go/build/build_test.go
+++ b/libgo/go/go/build/build_test.go
@@ -37,18 +37,20 @@ var buildPkgs = []struct {
{
"go/build/cmdtest",
&DirInfo{
- GoFiles: []string{"main.go"},
- Package: "main",
- Imports: []string{"go/build/pkgtest"},
+ GoFiles: []string{"main.go"},
+ Package: "main",
+ Imports: []string{"go/build/pkgtest"},
+ TestImports: []string{},
},
},
{
"go/build/cgotest",
&DirInfo{
- CgoFiles: []string{"cgotest.go"},
- CFiles: []string{"cgotest.c"},
- Imports: []string{"C", "unsafe"},
- Package: "cgotest",
+ CgoFiles: []string{"cgotest.go"},
+ CFiles: []string{"cgotest.c"},
+ Imports: []string{"C", "unsafe"},
+ TestImports: []string{},
+ Package: "cgotest",
},
},
}
diff --git a/libgo/go/go/printer/printer.go b/libgo/go/go/printer/printer.go
index aba7d93a64b..6104c326c66 100644
--- a/libgo/go/go/printer/printer.go
+++ b/libgo/go/go/printer/printer.go
@@ -13,6 +13,8 @@ import (
"io"
"os"
"path/filepath"
+ "strconv"
+ "strings"
"text/tabwriter"
)
@@ -244,6 +246,8 @@ func (p *printer) writeItem(pos token.Position, data string) {
p.last = p.pos
}
+const linePrefix = "//line "
+
// writeCommentPrefix writes the whitespace before a comment.
// If there is any pending whitespace, it consumes as much of
// it as is likely to help position the comment nicely.
@@ -252,7 +256,7 @@ func (p *printer) writeItem(pos token.Position, data string) {
// a group of comments (or nil), and isKeyword indicates if the
// next item is a keyword.
//
-func (p *printer) writeCommentPrefix(pos, next token.Position, prev *ast.Comment, isKeyword bool) {
+func (p *printer) writeCommentPrefix(pos, next token.Position, prev, comment *ast.Comment, isKeyword bool) {
if p.written == 0 {
// the comment is the first item to be printed - don't write any whitespace
return
@@ -337,6 +341,13 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, prev *ast.Comment
}
p.writeWhitespace(j)
}
+
+ // turn off indent if we're about to print a line directive.
+ indent := p.indent
+ if strings.HasPrefix(comment.Text, linePrefix) {
+ p.indent = 0
+ }
+
// use formfeeds to break columns before a comment;
// this is analogous to using formfeeds to separate
// individual lines of /*-style comments - but make
@@ -347,6 +358,7 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, prev *ast.Comment
n = 1
}
p.writeNewlines(n, true)
+ p.indent = indent
}
}
@@ -526,6 +538,26 @@ func stripCommonPrefix(lines [][]byte) {
func (p *printer) writeComment(comment *ast.Comment) {
text := comment.Text
+ if strings.HasPrefix(text, linePrefix) {
+ pos := strings.TrimSpace(text[len(linePrefix):])
+ i := strings.LastIndex(pos, ":")
+ if i >= 0 {
+ // The line directive we are about to print changed
+ // the Filename and Line number used by go/token
+ // as it was reading the input originally.
+ // In order to match the original input, we have to
+ // update our own idea of the file and line number
+ // accordingly, after printing the directive.
+ file := pos[:i]
+ line, _ := strconv.Atoi(string(pos[i+1:]))
+ defer func() {
+ p.pos.Filename = string(file)
+ p.pos.Line = line
+ p.pos.Column = 1
+ }()
+ }
+ }
+
// shortcut common case of //-style comments
if text[1] == '/' {
p.writeItem(p.fset.Position(comment.Pos()), p.escape(text))
@@ -599,7 +631,7 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (dro
var last *ast.Comment
for ; p.commentBefore(next); p.cindex++ {
for _, c := range p.comments[p.cindex].List {
- p.writeCommentPrefix(p.fset.Position(c.Pos()), next, last, tok.IsKeyword())
+ p.writeCommentPrefix(p.fset.Position(c.Pos()), next, last, c, tok.IsKeyword())
p.writeComment(c)
last = c
}
diff --git a/libgo/go/html/doc.go b/libgo/go/html/doc.go
index 1bea690c2c8..56b194ffb90 100644
--- a/libgo/go/html/doc.go
+++ b/libgo/go/html/doc.go
@@ -37,7 +37,7 @@ lower-cased, and attributes are collected into a []Attribute. For example:
for {
if z.Next() == html.ErrorToken {
// Returning io.EOF indicates success.
- return z.Error()
+ return z.Err()
}
emitToken(z.Token())
}
@@ -51,7 +51,7 @@ call to Next. For example, to extract an HTML page's anchor text:
tt := z.Next()
switch tt {
case ErrorToken:
- return z.Error()
+ return z.Err()
case TextToken:
if depth > 0 {
// emitBytes should copy the []byte it receives,
diff --git a/libgo/go/html/parse.go b/libgo/go/html/parse.go
index f47d4ea147c..9b7e934ac34 100644
--- a/libgo/go/html/parse.go
+++ b/libgo/go/html/parse.go
@@ -29,6 +29,8 @@ type parser struct {
head, form *Node
// Other parsing state flags (section 11.2.3.5).
scripting, framesetOK bool
+ // im is the current insertion mode.
+ im insertionMode
// originalIM is the insertion mode to go back to after completing a text
// or inTableText insertion mode.
originalIM insertionMode
@@ -265,37 +267,22 @@ func (p *parser) acknowledgeSelfClosingTag() {
// An insertion mode (section 11.2.3.1) is the state transition function from
// a particular state in the HTML5 parser's state machine. It updates the
-// parser's fields depending on parser.token (where ErrorToken means EOF). In
-// addition to returning the next insertionMode state, it also returns whether
-// the token was consumed.
-type insertionMode func(*parser) (insertionMode, bool)
-
-// useTheRulesFor runs the delegate insertionMode over p, returning the actual
-// insertionMode unless the delegate caused a state transition.
-// Section 11.2.3.1, "using the rules for".
-func useTheRulesFor(p *parser, actual, delegate insertionMode) (insertionMode, bool) {
- im, consumed := delegate(p)
- if p.originalIM == delegate {
- p.originalIM = actual
- }
- if im != delegate {
- return im, consumed
- }
- return actual, consumed
-}
+// parser's fields depending on parser.tok (where ErrorToken means EOF).
+// It returns whether the token was consumed.
+type insertionMode func(*parser) bool
// setOriginalIM sets the insertion mode to return to after completing a text or
// inTableText insertion mode.
// Section 11.2.3.1, "using the rules for".
-func (p *parser) setOriginalIM(im insertionMode) {
+func (p *parser) setOriginalIM() {
if p.originalIM != nil {
panic("html: bad parser state: originalIM was set twice")
}
- p.originalIM = im
+ p.originalIM = p.im
}
// Section 11.2.3.1, "reset the insertion mode".
-func (p *parser) resetInsertionMode() insertionMode {
+func (p *parser) resetInsertionMode() {
for i := len(p.oe) - 1; i >= 0; i-- {
n := p.oe[i]
if i == 0 {
@@ -303,95 +290,90 @@ func (p *parser) resetInsertionMode() insertionMode {
}
switch n.Data {
case "select":
- return inSelectIM
+ p.im = inSelectIM
case "td", "th":
- return inCellIM
+ p.im = inCellIM
case "tr":
- return inRowIM
+ p.im = inRowIM
case "tbody", "thead", "tfoot":
- return inTableBodyIM
+ p.im = inTableBodyIM
case "caption":
- // TODO: return inCaptionIM
+ p.im = inCaptionIM
case "colgroup":
- // TODO: return inColumnGroupIM
+ p.im = inColumnGroupIM
case "table":
- return inTableIM
+ p.im = inTableIM
case "head":
- return inBodyIM
+ p.im = inBodyIM
case "body":
- return inBodyIM
+ p.im = inBodyIM
case "frameset":
- // TODO: return inFramesetIM
+ p.im = inFramesetIM
case "html":
- return beforeHeadIM
+ p.im = beforeHeadIM
+ default:
+ continue
}
+ return
}
- return inBodyIM
+ p.im = inBodyIM
}
// Section 11.2.5.4.1.
-func initialIM(p *parser) (insertionMode, bool) {
+func initialIM(p *parser) bool {
switch p.tok.Type {
case CommentToken:
p.doc.Add(&Node{
Type: CommentNode,
Data: p.tok.Data,
})
- return initialIM, true
+ return true
case DoctypeToken:
p.doc.Add(&Node{
Type: DoctypeNode,
Data: p.tok.Data,
})
- return beforeHTMLIM, true
+ p.im = beforeHTMLIM
+ return true
}
// TODO: set "quirks mode"? It's defined in the DOM spec instead of HTML5 proper,
// and so switching on "quirks mode" might belong in a different package.
- return beforeHTMLIM, false
+ p.im = beforeHTMLIM
+ return false
}
// Section 11.2.5.4.2.
-func beforeHTMLIM(p *parser) (insertionMode, bool) {
- var (
- add bool
- attr []Attribute
- implied bool
- )
+func beforeHTMLIM(p *parser) bool {
switch p.tok.Type {
- case ErrorToken:
- implied = true
- case TextToken:
- // TODO: distinguish whitespace text from others.
- implied = true
case StartTagToken:
if p.tok.Data == "html" {
- add = true
- attr = p.tok.Attr
- } else {
- implied = true
+ p.addElement(p.tok.Data, p.tok.Attr)
+ p.im = beforeHeadIM
+ return true
}
case EndTagToken:
switch p.tok.Data {
case "head", "body", "html", "br":
- implied = true
+ // Drop down to creating an implied <html> tag.
default:
// Ignore the token.
+ return true
}
case CommentToken:
p.doc.Add(&Node{
Type: CommentNode,
Data: p.tok.Data,
})
- return beforeHTMLIM, true
- }
- if add || implied {
- p.addElement("html", attr)
+ return true
}
- return beforeHeadIM, !implied
+ // Create an implied <html> tag.
+ p.addElement("html", nil)
+ p.im = beforeHeadIM
+ return false
}
// Section 11.2.5.4.3.
-func beforeHeadIM(p *parser) (insertionMode, bool) {
+func beforeHeadIM(p *parser) bool {
var (
add bool
attr []Attribute
@@ -409,7 +391,7 @@ func beforeHeadIM(p *parser) (insertionMode, bool) {
add = true
attr = p.tok.Attr
case "html":
- return useTheRulesFor(p, beforeHeadIM, inBodyIM)
+ return inBodyIM(p)
default:
implied = true
}
@@ -425,19 +407,20 @@ func beforeHeadIM(p *parser) (insertionMode, bool) {
Type: CommentNode,
Data: p.tok.Data,
})
- return beforeHeadIM, true
+ return true
}
if add || implied {
p.addElement("head", attr)
p.head = p.top()
}
- return inHeadIM, !implied
+ p.im = inHeadIM
+ return !implied
}
const whitespace = " \t\r\n\f"
// Section 11.2.5.4.4.
-func inHeadIM(p *parser) (insertionMode, bool) {
+func inHeadIM(p *parser) bool {
var (
pop bool
implied bool
@@ -451,7 +434,7 @@ func inHeadIM(p *parser) (insertionMode, bool) {
// Add the initial whitespace to the current node.
p.addText(p.tok.Data[:len(p.tok.Data)-len(s)])
if s == "" {
- return inHeadIM, true
+ return true
}
p.tok.Data = s
}
@@ -464,35 +447,42 @@ func inHeadIM(p *parser) (insertionMode, bool) {
p.acknowledgeSelfClosingTag()
case "script", "title", "noscript", "noframes", "style":
p.addElement(p.tok.Data, p.tok.Attr)
- p.setOriginalIM(inHeadIM)
- return textIM, true
+ p.setOriginalIM()
+ p.im = textIM
+ return true
default:
implied = true
}
case EndTagToken:
- if p.tok.Data == "head" {
+ switch p.tok.Data {
+ case "head":
pop = true
+ case "body", "html", "br":
+ implied = true
+ default:
+ // Ignore the token.
+ return true
}
- // TODO.
case CommentToken:
p.addChild(&Node{
Type: CommentNode,
Data: p.tok.Data,
})
- return inHeadIM, true
+ return true
}
if pop || implied {
n := p.oe.pop()
if n.Data != "head" {
panic("html: bad parser state: <head> element not found, in the in-head insertion mode")
}
- return afterHeadIM, !implied
+ p.im = afterHeadIM
+ return !implied
}
- return inHeadIM, true
+ return true
}
// Section 11.2.5.4.6.
-func afterHeadIM(p *parser) (insertionMode, bool) {
+func afterHeadIM(p *parser) bool {
var (
add bool
attr []Attribute
@@ -512,11 +502,13 @@ func afterHeadIM(p *parser) (insertionMode, bool) {
attr = p.tok.Attr
framesetOK = false
case "frameset":
- // TODO.
+ p.addElement(p.tok.Data, p.tok.Attr)
+ p.im = inFramesetIM
+ return true
case "base", "basefont", "bgsound", "link", "meta", "noframes", "script", "style", "title":
p.oe = append(p.oe, p.head)
defer p.oe.pop()
- return useTheRulesFor(p, afterHeadIM, inHeadIM)
+ return inHeadIM(p)
case "head":
// TODO.
default:
@@ -524,19 +516,27 @@ func afterHeadIM(p *parser) (insertionMode, bool) {
framesetOK = true
}
case EndTagToken:
- // TODO.
+ switch p.tok.Data {
+ case "body", "html", "br":
+ implied = true
+ framesetOK = true
+ default:
+ // Ignore the token.
+ return true
+ }
case CommentToken:
p.addChild(&Node{
Type: CommentNode,
Data: p.tok.Data,
})
- return afterHeadIM, true
+ return true
}
if add || implied {
p.addElement("body", attr)
p.framesetOK = framesetOK
}
- return inBodyIM, !implied
+ p.im = inBodyIM
+ return !implied
}
// copyAttributes copies attributes of src not found on dst to dst.
@@ -557,7 +557,7 @@ func copyAttributes(dst *Node, src Token) {
}
// Section 11.2.5.4.7.
-func inBodyIM(p *parser) (insertionMode, bool) {
+func inBodyIM(p *parser) bool {
switch p.tok.Type {
case TextToken:
p.reconstructActiveFormattingElements()
@@ -604,7 +604,8 @@ func inBodyIM(p *parser) (insertionMode, bool) {
p.popUntil(buttonScopeStopTags, "p") // TODO: skip this step in quirks mode.
p.addElement(p.tok.Data, p.tok.Attr)
p.framesetOK = false
- return inTableIM, true
+ p.im = inTableIM
+ return true
case "hr":
p.popUntil(buttonScopeStopTags, "p")
p.addElement(p.tok.Data, p.tok.Attr)
@@ -616,7 +617,14 @@ func inBodyIM(p *parser) (insertionMode, bool) {
p.addElement(p.tok.Data, p.tok.Attr)
p.framesetOK = false
// TODO: detect <select> inside a table.
- return inSelectIM, true
+ p.im = inSelectIM
+ return true
+ case "form":
+ if p.form == nil {
+ p.popUntil(buttonScopeStopTags, "p")
+ p.addElement(p.tok.Data, p.tok.Attr)
+ p.form = p.top()
+ }
case "li":
p.framesetOK = false
for i := len(p.oe) - 1; i >= 0; i-- {
@@ -634,7 +642,28 @@ func inBodyIM(p *parser) (insertionMode, bool) {
break
}
p.popUntil(buttonScopeStopTags, "p")
- p.addElement("li", p.tok.Attr)
+ p.addElement(p.tok.Data, p.tok.Attr)
+ case "dd", "dt":
+ p.framesetOK = false
+ for i := len(p.oe) - 1; i >= 0; i-- {
+ node := p.oe[i]
+ switch node.Data {
+ case "dd", "dt":
+ p.oe = p.oe[:i]
+ case "address", "div", "p":
+ continue
+ default:
+ if !isSpecialElement[node.Data] {
+ continue
+ }
+ }
+ break
+ }
+ p.popUntil(buttonScopeStopTags, "p")
+ p.addElement(p.tok.Data, p.tok.Attr)
+ case "plaintext":
+ p.popUntil(buttonScopeStopTags, "p")
+ p.addElement(p.tok.Data, p.tok.Attr)
case "optgroup", "option":
if p.top().Data == "option" {
p.oe.pop()
@@ -650,10 +679,50 @@ func inBodyIM(p *parser) (insertionMode, bool) {
}
}
case "base", "basefont", "bgsound", "command", "link", "meta", "noframes", "script", "style", "title":
- return useTheRulesFor(p, inBodyIM, inHeadIM)
+ return inHeadIM(p)
case "image":
p.tok.Data = "img"
- return inBodyIM, false
+ return false
+ case "isindex":
+ if p.form != nil {
+ // Ignore the token.
+ return true
+ }
+ action := ""
+ prompt := "This is a searchable index. Enter search keywords: "
+ attr := []Attribute{{Key: "name", Val: "isindex"}}
+ for _, a := range p.tok.Attr {
+ switch a.Key {
+ case "action":
+ action = a.Val
+ case "name":
+ // Ignore the attribute.
+ case "prompt":
+ prompt = a.Val
+ default:
+ attr = append(attr, a)
+ }
+ }
+ p.acknowledgeSelfClosingTag()
+ p.popUntil(buttonScopeStopTags, "p")
+ p.addElement("form", nil)
+ p.form = p.top()
+ if action != "" {
+ p.form.Attr = []Attribute{{Key: "action", Val: action}}
+ }
+ p.addElement("hr", nil)
+ p.oe.pop()
+ p.addElement("label", nil)
+ p.addText(prompt)
+ p.addElement("input", attr)
+ p.oe.pop()
+ p.oe.pop()
+ p.addElement("hr", nil)
+ p.oe.pop()
+ p.oe.pop()
+ p.form = nil
+ case "caption", "col", "colgroup", "frame", "head", "tbody", "td", "tfoot", "th", "thead", "tr":
+ // Ignore the token.
default:
// TODO.
p.addElement(p.tok.Data, p.tok.Attr)
@@ -662,7 +731,8 @@ func inBodyIM(p *parser) (insertionMode, bool) {
switch p.tok.Data {
case "body":
// TODO: autoclose the stack of open elements.
- return afterBodyIM, true
+ p.im = afterBodyIM
+ return true
case "p":
if !p.elementInScope(buttonScopeStopTags, "p") {
p.addElement("p", nil)
@@ -676,6 +746,9 @@ func inBodyIM(p *parser) (insertionMode, bool) {
if p.popUntil(defaultScopeStopTags, p.tok.Data) {
p.clearActiveFormattingElements()
}
+ case "br":
+ p.tok.Type = StartTagToken
+ return false
default:
p.inBodyEndTagOther(p.tok.Data)
}
@@ -686,7 +759,7 @@ func inBodyIM(p *parser) (insertionMode, bool) {
})
}
- return inBodyIM, true
+ return true
}
func (p *parser) inBodyEndTagFormatting(tag string) {
@@ -827,45 +900,64 @@ func (p *parser) inBodyEndTagOther(tag string) {
}
// Section 11.2.5.4.8.
-func textIM(p *parser) (insertionMode, bool) {
+func textIM(p *parser) bool {
switch p.tok.Type {
case ErrorToken:
p.oe.pop()
case TextToken:
p.addText(p.tok.Data)
- return textIM, true
+ return true
case EndTagToken:
p.oe.pop()
}
- o := p.originalIM
+ p.im = p.originalIM
p.originalIM = nil
- return o, p.tok.Type == EndTagToken
+ return p.tok.Type == EndTagToken
}
// Section 11.2.5.4.9.
-func inTableIM(p *parser) (insertionMode, bool) {
+func inTableIM(p *parser) bool {
switch p.tok.Type {
case ErrorToken:
// Stop parsing.
- return nil, true
+ return true
case TextToken:
// TODO.
case StartTagToken:
switch p.tok.Data {
+ case "caption":
+ p.clearStackToContext(tableScopeStopTags)
+ p.afe = append(p.afe, &scopeMarker)
+ p.addElement(p.tok.Data, p.tok.Attr)
+ p.im = inCaptionIM
+ return true
case "tbody", "tfoot", "thead":
p.clearStackToContext(tableScopeStopTags)
p.addElement(p.tok.Data, p.tok.Attr)
- return inTableBodyIM, true
+ p.im = inTableBodyIM
+ return true
case "td", "th", "tr":
p.clearStackToContext(tableScopeStopTags)
p.addElement("tbody", nil)
- return inTableBodyIM, false
+ p.im = inTableBodyIM
+ return false
case "table":
if p.popUntil(tableScopeStopTags, "table") {
- return p.resetInsertionMode(), false
+ p.resetInsertionMode()
+ return false
}
// Ignore the token.
- return inTableIM, true
+ return true
+ case "colgroup":
+ p.clearStackToContext(tableScopeStopTags)
+ p.addElement(p.tok.Data, p.tok.Attr)
+ p.im = inColumnGroupIM
+ return true
+ case "col":
+ p.clearStackToContext(tableScopeStopTags)
+ p.addElement("colgroup", p.tok.Attr)
+ p.im = inColumnGroupIM
+ return false
default:
// TODO.
}
@@ -873,20 +965,21 @@ func inTableIM(p *parser) (insertionMode, bool) {
switch p.tok.Data {
case "table":
if p.popUntil(tableScopeStopTags, "table") {
- return p.resetInsertionMode(), true
+ p.resetInsertionMode()
+ return true
}
// Ignore the token.
- return inTableIM, true
+ return true
case "body", "caption", "col", "colgroup", "html", "tbody", "td", "tfoot", "th", "thead", "tr":
// Ignore the token.
- return inTableIM, true
+ return true
}
case CommentToken:
p.addChild(&Node{
Type: CommentNode,
Data: p.tok.Data,
})
- return inTableIM, true
+ return true
}
switch p.top().Data {
@@ -895,7 +988,7 @@ func inTableIM(p *parser) (insertionMode, bool) {
defer func() { p.fosterParenting = false }()
}
- return useTheRulesFor(p, inTableIM, inBodyIM)
+ return inBodyIM(p)
}
// clearStackToContext pops elements off the stack of open elements
@@ -911,8 +1004,90 @@ func (p *parser) clearStackToContext(stopTags []string) {
}
}
+// Section 11.2.5.4.11.
+func inCaptionIM(p *parser) bool {
+ switch p.tok.Type {
+ case StartTagToken:
+ switch p.tok.Data {
+ case "caption", "col", "colgroup", "tbody", "td", "tfoot", "thead", "tr":
+ if p.popUntil(tableScopeStopTags, "caption") {
+ p.clearActiveFormattingElements()
+ p.im = inTableIM
+ return false
+ } else {
+ // Ignore the token.
+ return true
+ }
+ }
+ case EndTagToken:
+ switch p.tok.Data {
+ case "caption":
+ if p.popUntil(tableScopeStopTags, "caption") {
+ p.clearActiveFormattingElements()
+ p.im = inTableIM
+ }
+ return true
+ case "table":
+ if p.popUntil(tableScopeStopTags, "caption") {
+ p.clearActiveFormattingElements()
+ p.im = inTableIM
+ return false
+ } else {
+ // Ignore the token.
+ return true
+ }
+ case "body", "col", "colgroup", "html", "tbody", "td", "tfoot", "th", "thead", "tr":
+ // Ignore the token.
+ return true
+ }
+ }
+ return inBodyIM(p)
+}
+
+// Section 11.2.5.4.12.
+func inColumnGroupIM(p *parser) bool {
+ switch p.tok.Type {
+ case CommentToken:
+ p.addChild(&Node{
+ Type: CommentNode,
+ Data: p.tok.Data,
+ })
+ return true
+ case DoctypeToken:
+ // Ignore the token.
+ return true
+ case StartTagToken:
+ switch p.tok.Data {
+ case "html":
+ return inBodyIM(p)
+ case "col":
+ p.addElement(p.tok.Data, p.tok.Attr)
+ p.oe.pop()
+ p.acknowledgeSelfClosingTag()
+ return true
+ }
+ case EndTagToken:
+ switch p.tok.Data {
+ case "colgroup":
+ if p.oe.top().Data != "html" {
+ p.oe.pop()
+ }
+ p.im = inTableIM
+ return true
+ case "col":
+ // Ignore the token.
+ return true
+ }
+ }
+ if p.oe.top().Data != "html" {
+ p.oe.pop()
+ }
+ p.im = inTableIM
+ return false
+}
+
// Section 11.2.5.4.13.
-func inTableBodyIM(p *parser) (insertionMode, bool) {
+func inTableBodyIM(p *parser) bool {
var (
add bool
data string
@@ -942,31 +1117,33 @@ func inTableBodyIM(p *parser) (insertionMode, bool) {
switch p.tok.Data {
case "table":
if p.popUntil(tableScopeStopTags, "tbody", "thead", "tfoot") {
- return inTableIM, false
+ p.im = inTableIM
+ return false
}
// Ignore the token.
- return inTableBodyIM, true
+ return true
case "body", "caption", "col", "colgroup", "html", "td", "th", "tr":
// Ignore the token.
- return inTableBodyIM, true
+ return true
}
case CommentToken:
p.addChild(&Node{
Type: CommentNode,
Data: p.tok.Data,
})
- return inTableBodyIM, true
+ return true
}
if add {
// TODO: clear the stack back to a table body context.
p.addElement(data, attr)
- return inRowIM, consumed
+ p.im = inRowIM
+ return consumed
}
- return useTheRulesFor(p, inTableBodyIM, inTableIM)
+ return inTableIM(p)
}
// Section 11.2.5.4.14.
-func inRowIM(p *parser) (insertionMode, bool) {
+func inRowIM(p *parser) bool {
switch p.tok.Type {
case ErrorToken:
// TODO.
@@ -978,13 +1155,15 @@ func inRowIM(p *parser) (insertionMode, bool) {
p.clearStackToContext(tableRowContextStopTags)
p.addElement(p.tok.Data, p.tok.Attr)
p.afe = append(p.afe, &scopeMarker)
- return inCellIM, true
+ p.im = inCellIM
+ return true
case "caption", "col", "colgroup", "tbody", "tfoot", "thead", "tr":
if p.popUntil(tableScopeStopTags, "tr") {
- return inTableBodyIM, false
+ p.im = inTableBodyIM
+ return false
}
// Ignore the token.
- return inRowIM, true
+ return true
default:
// TODO.
}
@@ -992,21 +1171,23 @@ func inRowIM(p *parser) (insertionMode, bool) {
switch p.tok.Data {
case "tr":
if p.popUntil(tableScopeStopTags, "tr") {
- return inTableBodyIM, true
+ p.im = inTableBodyIM
+ return true
}
// Ignore the token.
- return inRowIM, true
+ return true
case "table":
if p.popUntil(tableScopeStopTags, "tr") {
- return inTableBodyIM, false
+ p.im = inTableBodyIM
+ return false
}
// Ignore the token.
- return inRowIM, true
+ return true
case "tbody", "tfoot", "thead":
// TODO.
case "body", "caption", "col", "colgroup", "html", "td", "th":
// Ignore the token.
- return inRowIM, true
+ return true
default:
// TODO.
}
@@ -1015,13 +1196,13 @@ func inRowIM(p *parser) (insertionMode, bool) {
Type: CommentNode,
Data: p.tok.Data,
})
- return inRowIM, true
+ return true
}
- return useTheRulesFor(p, inRowIM, inTableIM)
+ return inTableIM(p)
}
// Section 11.2.5.4.15.
-func inCellIM(p *parser) (insertionMode, bool) {
+func inCellIM(p *parser) bool {
var (
closeTheCellAndReprocess bool
)
@@ -1037,10 +1218,11 @@ func inCellIM(p *parser) (insertionMode, bool) {
case "td", "th":
if !p.popUntil(tableScopeStopTags, p.tok.Data) {
// Ignore the token.
- return inCellIM, true
+ return true
}
p.clearActiveFormattingElements()
- return inRowIM, true
+ p.im = inRowIM
+ return true
case "body", "caption", "col", "colgroup", "html":
// TODO.
case "table", "tbody", "tfoot", "thead", "tr":
@@ -1052,19 +1234,20 @@ func inCellIM(p *parser) (insertionMode, bool) {
Type: CommentNode,
Data: p.tok.Data,
})
- return inCellIM, true
+ return true
}
if closeTheCellAndReprocess {
if p.popUntil(tableScopeStopTags, "td") || p.popUntil(tableScopeStopTags, "th") {
p.clearActiveFormattingElements()
- return inRowIM, false
+ p.im = inRowIM
+ return false
}
}
- return useTheRulesFor(p, inCellIM, inBodyIM)
+ return inBodyIM(p)
}
// Section 11.2.5.4.16.
-func inSelectIM(p *parser) (insertionMode, bool) {
+func inSelectIM(p *parser) bool {
endSelect := false
switch p.tok.Type {
case ErrorToken:
@@ -1081,7 +1264,13 @@ func inSelectIM(p *parser) (insertionMode, bool) {
}
p.addElement(p.tok.Data, p.tok.Attr)
case "optgroup":
- // TODO.
+ if p.top().Data == "option" {
+ p.oe.pop()
+ }
+ if p.top().Data == "optgroup" {
+ p.oe.pop()
+ }
+ p.addElement(p.tok.Data, p.tok.Attr)
case "select":
endSelect = true
case "input", "keygen", "textarea":
@@ -1094,9 +1283,17 @@ func inSelectIM(p *parser) (insertionMode, bool) {
case EndTagToken:
switch p.tok.Data {
case "option":
- // TODO.
+ if p.top().Data == "option" {
+ p.oe.pop()
+ }
case "optgroup":
- // TODO.
+ i := len(p.oe) - 1
+ if p.oe[i].Data == "option" {
+ i--
+ }
+ if p.oe[i].Data == "optgroup" {
+ p.oe = p.oe[:i]
+ }
case "select":
endSelect = true
default:
@@ -1113,34 +1310,33 @@ func inSelectIM(p *parser) (insertionMode, bool) {
switch p.oe[i].Data {
case "select":
p.oe = p.oe[:i]
- return p.resetInsertionMode(), true
+ p.resetInsertionMode()
+ return true
case "option", "optgroup":
continue
default:
// Ignore the token.
- return inSelectIM, true
+ return true
}
}
}
- return inSelectIM, true
+ return true
}
// Section 11.2.5.4.18.
-func afterBodyIM(p *parser) (insertionMode, bool) {
+func afterBodyIM(p *parser) bool {
switch p.tok.Type {
case ErrorToken:
- // TODO.
- case TextToken:
- // TODO.
+ // Stop parsing.
+ return true
case StartTagToken:
- // TODO.
+ if p.tok.Data == "html" {
+ return inBodyIM(p)
+ }
case EndTagToken:
- switch p.tok.Data {
- case "html":
- // TODO: autoclose the stack of open elements.
- return afterAfterBodyIM, true
- default:
- // TODO.
+ if p.tok.Data == "html" {
+ p.im = afterAfterBodyIM
+ return true
}
case CommentToken:
// The comment is attached to the <html> element.
@@ -1151,32 +1347,119 @@ func afterBodyIM(p *parser) (insertionMode, bool) {
Type: CommentNode,
Data: p.tok.Data,
})
- return afterBodyIM, true
+ return true
+ }
+ p.im = inBodyIM
+ return false
+}
+
+// Section 11.2.5.4.19.
+func inFramesetIM(p *parser) bool {
+ switch p.tok.Type {
+ case CommentToken:
+ p.addChild(&Node{
+ Type: CommentNode,
+ Data: p.tok.Data,
+ })
+ case StartTagToken:
+ switch p.tok.Data {
+ case "html":
+ return inBodyIM(p)
+ case "frameset":
+ p.addElement(p.tok.Data, p.tok.Attr)
+ case "frame":
+ p.addElement(p.tok.Data, p.tok.Attr)
+ p.oe.pop()
+ p.acknowledgeSelfClosingTag()
+ case "noframes":
+ return inHeadIM(p)
+ }
+ case EndTagToken:
+ switch p.tok.Data {
+ case "frameset":
+ if p.oe.top().Data != "html" {
+ p.oe.pop()
+ if p.oe.top().Data != "frameset" {
+ p.im = afterFramesetIM
+ return true
+ }
+ }
+ }
+ default:
+ // Ignore the token.
+ }
+ return true
+}
+
+// Section 11.2.5.4.20.
+func afterFramesetIM(p *parser) bool {
+ switch p.tok.Type {
+ case CommentToken:
+ p.addChild(&Node{
+ Type: CommentNode,
+ Data: p.tok.Data,
+ })
+ case StartTagToken:
+ switch p.tok.Data {
+ case "html":
+ return inBodyIM(p)
+ case "noframes":
+ return inHeadIM(p)
+ }
+ case EndTagToken:
+ switch p.tok.Data {
+ case "html":
+ p.im = afterAfterFramesetIM
+ return true
+ }
+ default:
+ // Ignore the token.
}
- // TODO: should this be "return inBodyIM, true"?
- return afterBodyIM, true
+ return true
}
// Section 11.2.5.4.21.
-func afterAfterBodyIM(p *parser) (insertionMode, bool) {
+func afterAfterBodyIM(p *parser) bool {
switch p.tok.Type {
case ErrorToken:
// Stop parsing.
- return nil, true
+ return true
case TextToken:
// TODO.
case StartTagToken:
if p.tok.Data == "html" {
- return useTheRulesFor(p, afterAfterBodyIM, inBodyIM)
+ return inBodyIM(p)
}
case CommentToken:
p.doc.Add(&Node{
Type: CommentNode,
Data: p.tok.Data,
})
- return afterAfterBodyIM, true
+ return true
+ }
+ p.im = inBodyIM
+ return false
+}
+
+// Section 11.2.5.4.22.
+func afterAfterFramesetIM(p *parser) bool {
+ switch p.tok.Type {
+ case CommentToken:
+ p.addChild(&Node{
+ Type: CommentNode,
+ Data: p.tok.Data,
+ })
+ case StartTagToken:
+ switch p.tok.Data {
+ case "html":
+ return inBodyIM(p)
+ case "noframes":
+ return inHeadIM(p)
+ }
+ default:
+ // Ignore the token.
}
- return inBodyIM, false
+ return true
}
// Parse returns the parse tree for the HTML from the given Reader.
@@ -1189,9 +1472,10 @@ func Parse(r io.Reader) (*Node, error) {
},
scripting: true,
framesetOK: true,
+ im: initialIM,
}
// Iterate until EOF. Any other error will cause an early return.
- im, consumed := initialIM, true
+ consumed := true
for {
if consumed {
if err := p.read(); err != nil {
@@ -1201,11 +1485,11 @@ func Parse(r io.Reader) (*Node, error) {
return nil, err
}
}
- im, consumed = im(p)
+ consumed = p.im(p)
}
// Loop until the final token (the ErrorToken signifying EOF) is consumed.
for {
- if im, consumed = im(p); consumed {
+ if consumed = p.im(p); consumed {
break
}
}
diff --git a/libgo/go/html/parse_test.go b/libgo/go/html/parse_test.go
index 27979225b33..4f15ae1d554 100644
--- a/libgo/go/html/parse_test.go
+++ b/libgo/go/html/parse_test.go
@@ -133,8 +133,8 @@ func TestParser(t *testing.T) {
n int
}{
// TODO(nigeltao): Process all the test cases from all the .dat files.
- {"tests1.dat", 92},
- {"tests2.dat", 0},
+ {"tests1.dat", -1},
+ {"tests2.dat", 43},
{"tests3.dat", 0},
}
for _, tf := range testFiles {
@@ -213,4 +213,8 @@ var renderTestBlacklist = map[string]bool{
// More cases of <a> being reparented:
`<a href="blah">aba<table><a href="foo">br<tr><td></td></tr>x</table>aoe`: true,
`<a><table><a></table><p><a><div><a>`: true,
+ `<a><table><td><a><table></table><a></tr><a></table><a>`: true,
+ // A <plaintext> element is reparented, putting it before a table.
+ // A <plaintext> element can't have anything after it in HTML.
+ `<table><plaintext><td>`: true,
}
diff --git a/libgo/go/html/render.go b/libgo/go/html/render.go
index c815f35f1e1..92c349fb32c 100644
--- a/libgo/go/html/render.go
+++ b/libgo/go/html/render.go
@@ -52,7 +52,19 @@ func Render(w io.Writer, n *Node) error {
return buf.Flush()
}
+// plaintextAbort is returned from render1 when a <plaintext> element
+// has been rendered. No more end tags should be rendered after that.
+var plaintextAbort = errors.New("html: internal error (plaintext abort)")
+
func render(w writer, n *Node) error {
+ err := render1(w, n)
+ if err == plaintextAbort {
+ err = nil
+ }
+ return err
+}
+
+func render1(w writer, n *Node) error {
// Render non-element nodes; these are the easy cases.
switch n.Type {
case ErrorNode:
@@ -61,7 +73,7 @@ func render(w writer, n *Node) error {
return escape(w, n.Data)
case DocumentNode:
for _, c := range n.Child {
- if err := render(w, c); err != nil {
+ if err := render1(w, c); err != nil {
return err
}
}
@@ -128,7 +140,7 @@ func render(w writer, n *Node) error {
// Render any child nodes.
switch n.Data {
- case "noembed", "noframes", "noscript", "script", "style":
+ case "noembed", "noframes", "noscript", "plaintext", "script", "style":
for _, c := range n.Child {
if c.Type != TextNode {
return fmt.Errorf("html: raw text element <%s> has non-text child node", n.Data)
@@ -137,18 +149,23 @@ func render(w writer, n *Node) error {
return err
}
}
+ if n.Data == "plaintext" {
+ // Don't render anything else. <plaintext> must be the
+ // last element in the file, with no closing tag.
+ return plaintextAbort
+ }
case "textarea", "title":
for _, c := range n.Child {
if c.Type != TextNode {
return fmt.Errorf("html: RCDATA element <%s> has non-text child node", n.Data)
}
- if err := render(w, c); err != nil {
+ if err := render1(w, c); err != nil {
return err
}
}
default:
for _, c := range n.Child {
- if err := render(w, c); err != nil {
+ if err := render1(w, c); err != nil {
return err
}
}
diff --git a/libgo/go/html/template/content.go b/libgo/go/html/template/content.go
index d720d4ba689..3fb15a6e93f 100644
--- a/libgo/go/html/template/content.go
+++ b/libgo/go/html/template/content.go
@@ -6,6 +6,7 @@ package template
import (
"fmt"
+ "reflect"
)
// Strings of content from a trusted source.
@@ -70,10 +71,25 @@ const (
contentTypeUnsafe
)
+// indirect returns the value, after dereferencing as many times
+// as necessary to reach the base type (or nil).
+func indirect(a interface{}) interface{} {
+ if t := reflect.TypeOf(a); t.Kind() != reflect.Ptr {
+ // Avoid creating a reflect.Value if it's not a pointer.
+ return a
+ }
+ v := reflect.ValueOf(a)
+ for v.Kind() == reflect.Ptr && !v.IsNil() {
+ v = v.Elem()
+ }
+ return v.Interface()
+}
+
// stringify converts its arguments to a string and the type of the content.
+// All pointers are dereferenced, as in the text/template package.
func stringify(args ...interface{}) (string, contentType) {
if len(args) == 1 {
- switch s := args[0].(type) {
+ switch s := indirect(args[0]).(type) {
case string:
return s, contentTypePlain
case CSS:
@@ -90,5 +106,8 @@ func stringify(args ...interface{}) (string, contentType) {
return string(s), contentTypeURL
}
}
+ for i, arg := range args {
+ args[i] = indirect(arg)
+ }
return fmt.Sprint(args...), contentTypePlain
}
diff --git a/libgo/go/html/template/escape_test.go b/libgo/go/html/template/escape_test.go
index d8bfa321121..4af583097bd 100644
--- a/libgo/go/html/template/escape_test.go
+++ b/libgo/go/html/template/escape_test.go
@@ -28,7 +28,7 @@ func (x *goodMarshaler) MarshalJSON() ([]byte, error) {
}
func TestEscape(t *testing.T) {
- var data = struct {
+ data := struct {
F, T bool
C, G, H string
A, E []string
@@ -50,6 +50,7 @@ func TestEscape(t *testing.T) {
Z: nil,
W: HTML(`&iexcl;<b class="foo">Hello</b>, <textarea>O'World</textarea>!`),
}
+ pdata := &data
tests := []struct {
name string
@@ -668,6 +669,15 @@ func TestEscape(t *testing.T) {
t.Errorf("%s: escaped output: want\n\t%q\ngot\n\t%q", test.name, w, g)
continue
}
+ b.Reset()
+ if err := tmpl.Execute(b, pdata); err != nil {
+ t.Errorf("%s: template execution failed for pointer: %s", test.name, err)
+ continue
+ }
+ if w, g := test.output, b.String(); w != g {
+ t.Errorf("%s: escaped output for pointer: want\n\t%q\ngot\n\t%q", test.name, w, g)
+ continue
+ }
}
}
@@ -1605,6 +1615,29 @@ func TestRedundantFuncs(t *testing.T) {
}
}
+func TestIndirectPrint(t *testing.T) {
+ a := 3
+ ap := &a
+ b := "hello"
+ bp := &b
+ bpp := &bp
+ tmpl := Must(New("t").Parse(`{{.}}`))
+ var buf bytes.Buffer
+ err := tmpl.Execute(&buf, ap)
+ if err != nil {
+ t.Errorf("Unexpected error: %s", err)
+ } else if buf.String() != "3" {
+ t.Errorf(`Expected "3"; got %q`, buf.String())
+ }
+ buf.Reset()
+ err = tmpl.Execute(&buf, bpp)
+ if err != nil {
+ t.Errorf("Unexpected error: %s", err)
+ } else if buf.String() != "hello" {
+ t.Errorf(`Expected "hello"; got %q`, buf.String())
+ }
+}
+
func BenchmarkEscapedExecute(b *testing.B) {
tmpl := Must(New("t").Parse(`<a onclick="alert('{{.}}')">{{.}}</a>`))
var buf bytes.Buffer
diff --git a/libgo/go/html/template/js.go b/libgo/go/html/template/js.go
index 68c53e5ca3b..0e632df4220 100644
--- a/libgo/go/html/template/js.go
+++ b/libgo/go/html/template/js.go
@@ -8,6 +8,7 @@ import (
"bytes"
"encoding/json"
"fmt"
+ "reflect"
"strings"
"unicode/utf8"
)
@@ -117,12 +118,24 @@ var regexpPrecederKeywords = map[string]bool{
"void": true,
}
+var jsonMarshalType = reflect.TypeOf((*json.Marshaler)(nil)).Elem()
+
+// indirectToJSONMarshaler returns the value, after dereferencing as many times
+// as necessary to reach the base type (or nil) or an implementation of json.Marshal.
+func indirectToJSONMarshaler(a interface{}) interface{} {
+ v := reflect.ValueOf(a)
+ for !v.Type().Implements(jsonMarshalType) && v.Kind() == reflect.Ptr && !v.IsNil() {
+ v = v.Elem()
+ }
+ return v.Interface()
+}
+
// jsValEscaper escapes its inputs to a JS Expression (section 11.14) that has
-// nether side-effects nor free variables outside (NaN, Infinity).
+// neither side-effects nor free variables outside (NaN, Infinity).
func jsValEscaper(args ...interface{}) string {
var a interface{}
if len(args) == 1 {
- a = args[0]
+ a = indirectToJSONMarshaler(args[0])
switch t := a.(type) {
case JS:
return string(t)
@@ -135,6 +148,9 @@ func jsValEscaper(args ...interface{}) string {
a = t.String()
}
} else {
+ for i, arg := range args {
+ args[i] = indirectToJSONMarshaler(arg)
+ }
a = fmt.Sprint(args...)
}
// TODO: detect cycles before calling Marshal which loops infinitely on
diff --git a/libgo/go/html/token.go b/libgo/go/html/token.go
index 2c138227b10..9400873e6b8 100644
--- a/libgo/go/html/token.go
+++ b/libgo/go/html/token.go
@@ -401,14 +401,14 @@ func (z *Tokenizer) readStartTag() TokenType {
break
}
}
- // Any "<noembed>", "<noframes>", "<noscript>", "<script>", "<style>",
+ // Any "<noembed>", "<noframes>", "<noscript>", "<plaintext", "<script>", "<style>",
// "<textarea>" or "<title>" tag flags the tokenizer's next token as raw.
- // The tag name lengths of these special cases ranges in [5, 8].
- if x := z.data.end - z.data.start; 5 <= x && x <= 8 {
+ // The tag name lengths of these special cases ranges in [5, 9].
+ if x := z.data.end - z.data.start; 5 <= x && x <= 9 {
switch z.buf[z.data.start] {
- case 'n', 's', 't', 'N', 'S', 'T':
+ case 'n', 'p', 's', 't', 'N', 'P', 'S', 'T':
switch s := strings.ToLower(string(z.buf[z.data.start:z.data.end])); s {
- case "noembed", "noframes", "noscript", "script", "style", "textarea", "title":
+ case "noembed", "noframes", "noscript", "plaintext", "script", "style", "textarea", "title":
z.rawTag = s
}
}
@@ -551,9 +551,19 @@ func (z *Tokenizer) Next() TokenType {
z.data.start = z.raw.end
z.data.end = z.raw.end
if z.rawTag != "" {
- z.readRawOrRCDATA()
- z.tt = TextToken
- return z.tt
+ if z.rawTag == "plaintext" {
+ // Read everything up to EOF.
+ for z.err == nil {
+ z.readByte()
+ }
+ z.textIsRaw = true
+ } else {
+ z.readRawOrRCDATA()
+ }
+ if z.data.end > z.data.start {
+ z.tt = TextToken
+ return z.tt
+ }
}
z.textIsRaw = false
diff --git a/libgo/go/image/tiff/buffer.go b/libgo/go/image/tiff/buffer.go
index ce350738ed8..27533c6047d 100644
--- a/libgo/go/image/tiff/buffer.go
+++ b/libgo/go/image/tiff/buffer.go
@@ -4,10 +4,7 @@
package tiff
-import (
- "io"
- "os"
-)
+import "io"
// buffer buffers an io.Reader to satisfy io.ReaderAt.
type buffer struct {
@@ -19,7 +16,7 @@ func (b *buffer) ReadAt(p []byte, off int64) (int, error) {
o := int(off)
end := o + len(p)
if int64(end) != off+int64(len(p)) {
- return 0, os.EINVAL
+ return 0, io.ErrUnexpectedEOF
}
m := len(b.buf)
diff --git a/libgo/go/io/ioutil/tempfile.go b/libgo/go/io/ioutil/tempfile.go
index 658ea78bb7c..71028e22677 100644
--- a/libgo/go/io/ioutil/tempfile.go
+++ b/libgo/go/io/ioutil/tempfile.go
@@ -8,6 +8,7 @@ import (
"os"
"path/filepath"
"strconv"
+ "time"
)
// Random number state, accessed without lock; racy but harmless.
@@ -17,8 +18,7 @@ import (
var rand uint32
func reseed() uint32 {
- sec, nsec, _ := os.Time()
- return uint32(sec*1e9 + nsec + int64(os.Getpid()))
+ return uint32(time.Nanoseconds() + int64(os.Getpid()))
}
func nextSuffix() string {
diff --git a/libgo/go/log/syslog/syslog.go b/libgo/go/log/syslog/syslog.go
index 26a2f736b17..546bc296a5f 100644
--- a/libgo/go/log/syslog/syslog.go
+++ b/libgo/go/log/syslog/syslog.go
@@ -8,6 +8,7 @@
package syslog
import (
+ "errors"
"fmt"
"log"
"net"
@@ -75,7 +76,7 @@ func Dial(network, raddr string, priority Priority, prefix string) (w *Writer, e
// Write sends a log message to the syslog daemon.
func (w *Writer) Write(b []byte) (int, error) {
if w.priority > LOG_DEBUG || w.priority < LOG_EMERG {
- return 0, os.EINVAL
+ return 0, errors.New("log/syslog: invalid priority")
}
return w.conn.writeBytes(w.priority, w.prefix, b)
}
diff --git a/libgo/go/math/big/int.go b/libgo/go/math/big/int.go
index 533a97f7495..35e2e294183 100644
--- a/libgo/go/math/big/int.go
+++ b/libgo/go/math/big/int.go
@@ -176,7 +176,7 @@ func (z *Int) Quo(x, y *Int) *Int {
// If y == 0, a division-by-zero run-time panic occurs.
// Rem implements truncated modulus (like Go); see QuoRem for more details.
func (z *Int) Rem(x, y *Int) *Int {
- _, z.abs = nat{}.div(z.abs, x.abs, y.abs)
+ _, z.abs = nat(nil).div(z.abs, x.abs, y.abs)
z.neg = len(z.abs) > 0 && x.neg // 0 has no sign
return z
}
@@ -678,14 +678,14 @@ func (z *Int) Bit(i int) uint {
panic("negative bit index")
}
if z.neg {
- t := nat{}.sub(z.abs, natOne)
+ t := nat(nil).sub(z.abs, natOne)
return t.bit(uint(i)) ^ 1
}
return z.abs.bit(uint(i))
}
-// SetBit sets the i'th bit of z to bit and returns z.
+// SetBit sets z to x, with x's i'th bit set to b (0 or 1).
// That is, if bit is 1 SetBit sets z = x | (1 << i);
// if bit is 0 it sets z = x &^ (1 << i). If bit is not 0 or 1,
// SetBit will panic.
@@ -710,8 +710,8 @@ func (z *Int) And(x, y *Int) *Int {
if x.neg == y.neg {
if x.neg {
// (-x) & (-y) == ^(x-1) & ^(y-1) == ^((x-1) | (y-1)) == -(((x-1) | (y-1)) + 1)
- x1 := nat{}.sub(x.abs, natOne)
- y1 := nat{}.sub(y.abs, natOne)
+ x1 := nat(nil).sub(x.abs, natOne)
+ y1 := nat(nil).sub(y.abs, natOne)
z.abs = z.abs.add(z.abs.or(x1, y1), natOne)
z.neg = true // z cannot be zero if x and y are negative
return z
@@ -729,7 +729,7 @@ func (z *Int) And(x, y *Int) *Int {
}
// x & (-y) == x & ^(y-1) == x &^ (y-1)
- y1 := nat{}.sub(y.abs, natOne)
+ y1 := nat(nil).sub(y.abs, natOne)
z.abs = z.abs.andNot(x.abs, y1)
z.neg = false
return z
@@ -740,8 +740,8 @@ func (z *Int) AndNot(x, y *Int) *Int {
if x.neg == y.neg {
if x.neg {
// (-x) &^ (-y) == ^(x-1) &^ ^(y-1) == ^(x-1) & (y-1) == (y-1) &^ (x-1)
- x1 := nat{}.sub(x.abs, natOne)
- y1 := nat{}.sub(y.abs, natOne)
+ x1 := nat(nil).sub(x.abs, natOne)
+ y1 := nat(nil).sub(y.abs, natOne)
z.abs = z.abs.andNot(y1, x1)
z.neg = false
return z
@@ -755,14 +755,14 @@ func (z *Int) AndNot(x, y *Int) *Int {
if x.neg {
// (-x) &^ y == ^(x-1) &^ y == ^(x-1) & ^y == ^((x-1) | y) == -(((x-1) | y) + 1)
- x1 := nat{}.sub(x.abs, natOne)
+ x1 := nat(nil).sub(x.abs, natOne)
z.abs = z.abs.add(z.abs.or(x1, y.abs), natOne)
z.neg = true // z cannot be zero if x is negative and y is positive
return z
}
// x &^ (-y) == x &^ ^(y-1) == x & (y-1)
- y1 := nat{}.add(y.abs, natOne)
+ y1 := nat(nil).add(y.abs, natOne)
z.abs = z.abs.and(x.abs, y1)
z.neg = false
return z
@@ -773,8 +773,8 @@ func (z *Int) Or(x, y *Int) *Int {
if x.neg == y.neg {
if x.neg {
// (-x) | (-y) == ^(x-1) | ^(y-1) == ^((x-1) & (y-1)) == -(((x-1) & (y-1)) + 1)
- x1 := nat{}.sub(x.abs, natOne)
- y1 := nat{}.sub(y.abs, natOne)
+ x1 := nat(nil).sub(x.abs, natOne)
+ y1 := nat(nil).sub(y.abs, natOne)
z.abs = z.abs.add(z.abs.and(x1, y1), natOne)
z.neg = true // z cannot be zero if x and y are negative
return z
@@ -792,7 +792,7 @@ func (z *Int) Or(x, y *Int) *Int {
}
// x | (-y) == x | ^(y-1) == ^((y-1) &^ x) == -(^((y-1) &^ x) + 1)
- y1 := nat{}.sub(y.abs, natOne)
+ y1 := nat(nil).sub(y.abs, natOne)
z.abs = z.abs.add(z.abs.andNot(y1, x.abs), natOne)
z.neg = true // z cannot be zero if one of x or y is negative
return z
@@ -803,8 +803,8 @@ func (z *Int) Xor(x, y *Int) *Int {
if x.neg == y.neg {
if x.neg {
// (-x) ^ (-y) == ^(x-1) ^ ^(y-1) == (x-1) ^ (y-1)
- x1 := nat{}.sub(x.abs, natOne)
- y1 := nat{}.sub(y.abs, natOne)
+ x1 := nat(nil).sub(x.abs, natOne)
+ y1 := nat(nil).sub(y.abs, natOne)
z.abs = z.abs.xor(x1, y1)
z.neg = false
return z
@@ -822,7 +822,7 @@ func (z *Int) Xor(x, y *Int) *Int {
}
// x ^ (-y) == x ^ ^(y-1) == ^(x ^ (y-1)) == -((x ^ (y-1)) + 1)
- y1 := nat{}.sub(y.abs, natOne)
+ y1 := nat(nil).sub(y.abs, natOne)
z.abs = z.abs.add(z.abs.xor(x.abs, y1), natOne)
z.neg = true // z cannot be zero if only one of x or y is negative
return z
diff --git a/libgo/go/math/big/nat.go b/libgo/go/math/big/nat.go
index 3fa41e7565f..eee8ee3f66c 100644
--- a/libgo/go/math/big/nat.go
+++ b/libgo/go/math/big/nat.go
@@ -447,10 +447,10 @@ func (z nat) mulRange(a, b uint64) nat {
case a == b:
return z.setUint64(a)
case a+1 == b:
- return z.mul(nat{}.setUint64(a), nat{}.setUint64(b))
+ return z.mul(nat(nil).setUint64(a), nat(nil).setUint64(b))
}
m := (a + b) / 2
- return z.mul(nat{}.mulRange(a, m), nat{}.mulRange(m+1, b))
+ return z.mul(nat(nil).mulRange(a, m), nat(nil).mulRange(m+1, b))
}
// q = (x-r)/y, with 0 <= r < y
@@ -785,7 +785,7 @@ func (x nat) string(charset string) string {
}
// preserve x, create local copy for use in repeated divisions
- q := nat{}.set(x)
+ q := nat(nil).set(x)
var r Word
// convert
@@ -1191,11 +1191,11 @@ func (n nat) probablyPrime(reps int) bool {
return false
}
- nm1 := nat{}.sub(n, natOne)
+ nm1 := nat(nil).sub(n, natOne)
// 1<<k * q = nm1;
q, k := nm1.powersOfTwoDecompose()
- nm3 := nat{}.sub(nm1, natTwo)
+ nm3 := nat(nil).sub(nm1, natTwo)
rand := rand.New(rand.NewSource(int64(n[0])))
var x, y, quotient nat
diff --git a/libgo/go/math/big/nat_test.go b/libgo/go/math/big/nat_test.go
index 041a6c4a255..b208646f2f2 100644
--- a/libgo/go/math/big/nat_test.go
+++ b/libgo/go/math/big/nat_test.go
@@ -16,9 +16,9 @@ var cmpTests = []struct {
r int
}{
{nil, nil, 0},
- {nil, nat{}, 0},
- {nat{}, nil, 0},
- {nat{}, nat{}, 0},
+ {nil, nat(nil), 0},
+ {nat(nil), nil, 0},
+ {nat(nil), nat(nil), 0},
{nat{0}, nat{0}, 0},
{nat{0}, nat{1}, -1},
{nat{1}, nat{0}, 1},
@@ -67,7 +67,7 @@ var prodNN = []argNN{
func TestSet(t *testing.T) {
for _, a := range sumNN {
- z := nat{}.set(a.z)
+ z := nat(nil).set(a.z)
if z.cmp(a.z) != 0 {
t.Errorf("got z = %v; want %v", z, a.z)
}
@@ -129,7 +129,7 @@ var mulRangesN = []struct {
func TestMulRangeN(t *testing.T) {
for i, r := range mulRangesN {
- prod := nat{}.mulRange(r.a, r.b).decimalString()
+ prod := nat(nil).mulRange(r.a, r.b).decimalString()
if prod != r.prod {
t.Errorf("#%d: got %s; want %s", i, prod, r.prod)
}
@@ -175,7 +175,7 @@ func toString(x nat, charset string) string {
s := make([]byte, i)
// don't destroy x
- q := nat{}.set(x)
+ q := nat(nil).set(x)
// convert
for len(q) > 0 {
@@ -212,7 +212,7 @@ func TestString(t *testing.T) {
t.Errorf("string%+v\n\tgot s = %s; want %s", a, s, a.s)
}
- x, b, err := nat{}.scan(strings.NewReader(a.s), len(a.c))
+ x, b, err := nat(nil).scan(strings.NewReader(a.s), len(a.c))
if x.cmp(a.x) != 0 {
t.Errorf("scan%+v\n\tgot z = %v; want %v", a, x, a.x)
}
@@ -271,7 +271,7 @@ var natScanTests = []struct {
func TestScanBase(t *testing.T) {
for _, a := range natScanTests {
r := strings.NewReader(a.s)
- x, b, err := nat{}.scan(r, a.base)
+ x, b, err := nat(nil).scan(r, a.base)
if err == nil && !a.ok {
t.Errorf("scan%+v\n\texpected error", a)
}
@@ -651,17 +651,17 @@ var expNNTests = []struct {
func TestExpNN(t *testing.T) {
for i, test := range expNNTests {
- x, _, _ := nat{}.scan(strings.NewReader(test.x), 0)
- y, _, _ := nat{}.scan(strings.NewReader(test.y), 0)
- out, _, _ := nat{}.scan(strings.NewReader(test.out), 0)
+ x, _, _ := nat(nil).scan(strings.NewReader(test.x), 0)
+ y, _, _ := nat(nil).scan(strings.NewReader(test.y), 0)
+ out, _, _ := nat(nil).scan(strings.NewReader(test.out), 0)
var m nat
if len(test.m) > 0 {
- m, _, _ = nat{}.scan(strings.NewReader(test.m), 0)
+ m, _, _ = nat(nil).scan(strings.NewReader(test.m), 0)
}
- z := nat{}.expNN(x, y, m)
+ z := nat(nil).expNN(x, y, m)
if z.cmp(out) != 0 {
t.Errorf("#%d got %v want %v", i, z, out)
}
diff --git a/libgo/go/math/big/rat.go b/libgo/go/math/big/rat.go
index 3a0add32363..adf412485f6 100644
--- a/libgo/go/math/big/rat.go
+++ b/libgo/go/math/big/rat.go
@@ -33,7 +33,7 @@ func (z *Rat) SetFrac(a, b *Int) *Rat {
panic("division by zero")
}
if &z.a == b || alias(z.a.abs, babs) {
- babs = nat{}.set(babs) // make a copy
+ babs = nat(nil).set(babs) // make a copy
}
z.a.abs = z.a.abs.set(a.abs)
z.b = z.b.set(babs)
@@ -315,7 +315,7 @@ func (z *Rat) SetString(s string) (*Rat, bool) {
if _, ok := z.a.SetString(s, 10); !ok {
return nil, false
}
- powTen := nat{}.expNN(natTen, exp.abs, nil)
+ powTen := nat(nil).expNN(natTen, exp.abs, nil)
if exp.neg {
z.b = powTen
z.norm()
@@ -357,23 +357,23 @@ func (z *Rat) FloatString(prec int) string {
}
// z.b != 0
- q, r := nat{}.div(nat{}, z.a.abs, z.b)
+ q, r := nat(nil).div(nat(nil), z.a.abs, z.b)
p := natOne
if prec > 0 {
- p = nat{}.expNN(natTen, nat{}.setUint64(uint64(prec)), nil)
+ p = nat(nil).expNN(natTen, nat(nil).setUint64(uint64(prec)), nil)
}
r = r.mul(r, p)
- r, r2 := r.div(nat{}, r, z.b)
+ r, r2 := r.div(nat(nil), r, z.b)
// see if we need to round up
r2 = r2.add(r2, r2)
if z.b.cmp(r2) <= 0 {
r = r.add(r, natOne)
if r.cmp(p) >= 0 {
- q = nat{}.add(q, natOne)
- r = nat{}.sub(r, p)
+ q = nat(nil).add(q, natOne)
+ r = nat(nil).sub(r, p)
}
}
diff --git a/libgo/go/math/gamma.go b/libgo/go/math/gamma.go
index e117158fee2..ae2c0c418ab 100644
--- a/libgo/go/math/gamma.go
+++ b/libgo/go/math/gamma.go
@@ -63,7 +63,7 @@ package math
// Stephen L. Moshier
// moshier@na-net.ornl.gov
-var _P = [...]float64{
+var _gamP = [...]float64{
1.60119522476751861407e-04,
1.19135147006586384913e-03,
1.04213797561761569935e-02,
@@ -72,7 +72,7 @@ var _P = [...]float64{
4.94214826801497100753e-01,
9.99999999999999996796e-01,
}
-var _Q = [...]float64{
+var _gamQ = [...]float64{
-2.31581873324120129819e-05,
5.39605580493303397842e-04,
-4.45641913851797240494e-03,
@@ -82,7 +82,7 @@ var _Q = [...]float64{
7.14304917030273074085e-02,
1.00000000000000000320e+00,
}
-var _S = [...]float64{
+var _gamS = [...]float64{
7.87311395793093628397e-04,
-2.29549961613378126380e-04,
-2.68132617805781232825e-03,
@@ -98,7 +98,7 @@ func stirling(x float64) float64 {
MaxStirling = 143.01608
)
w := 1 / x
- w = 1 + w*((((_S[0]*w+_S[1])*w+_S[2])*w+_S[3])*w+_S[4])
+ w = 1 + w*((((_gamS[0]*w+_gamS[1])*w+_gamS[2])*w+_gamS[3])*w+_gamS[4])
y := Exp(x)
if x > MaxStirling { // avoid Pow() overflow
v := Pow(x, 0.5*x-0.25)
@@ -176,8 +176,8 @@ func Gamma(x float64) float64 {
}
x = x - 2
- p = (((((x*_P[0]+_P[1])*x+_P[2])*x+_P[3])*x+_P[4])*x+_P[5])*x + _P[6]
- q = ((((((x*_Q[0]+_Q[1])*x+_Q[2])*x+_Q[3])*x+_Q[4])*x+_Q[5])*x+_Q[6])*x + _Q[7]
+ p = (((((x*_gamP[0]+_gamP[1])*x+_gamP[2])*x+_gamP[3])*x+_gamP[4])*x+_gamP[5])*x + _gamP[6]
+ q = ((((((x*_gamQ[0]+_gamQ[1])*x+_gamQ[2])*x+_gamQ[3])*x+_gamQ[4])*x+_gamQ[5])*x+_gamQ[6])*x + _gamQ[7]
return z * p / q
small:
diff --git a/libgo/go/math/lgamma.go b/libgo/go/math/lgamma.go
index 8f6d7b99fc5..e2bad69dc03 100644
--- a/libgo/go/math/lgamma.go
+++ b/libgo/go/math/lgamma.go
@@ -88,6 +88,81 @@ package math
//
//
+var _lgamA = [...]float64{
+ 7.72156649015328655494e-02, // 0x3FB3C467E37DB0C8
+ 3.22467033424113591611e-01, // 0x3FD4A34CC4A60FAD
+ 6.73523010531292681824e-02, // 0x3FB13E001A5562A7
+ 2.05808084325167332806e-02, // 0x3F951322AC92547B
+ 7.38555086081402883957e-03, // 0x3F7E404FB68FEFE8
+ 2.89051383673415629091e-03, // 0x3F67ADD8CCB7926B
+ 1.19270763183362067845e-03, // 0x3F538A94116F3F5D
+ 5.10069792153511336608e-04, // 0x3F40B6C689B99C00
+ 2.20862790713908385557e-04, // 0x3F2CF2ECED10E54D
+ 1.08011567247583939954e-04, // 0x3F1C5088987DFB07
+ 2.52144565451257326939e-05, // 0x3EFA7074428CFA52
+ 4.48640949618915160150e-05, // 0x3F07858E90A45837
+}
+var _lgamR = [...]float64{
+ 1.0, // placeholder
+ 1.39200533467621045958e+00, // 0x3FF645A762C4AB74
+ 7.21935547567138069525e-01, // 0x3FE71A1893D3DCDC
+ 1.71933865632803078993e-01, // 0x3FC601EDCCFBDF27
+ 1.86459191715652901344e-02, // 0x3F9317EA742ED475
+ 7.77942496381893596434e-04, // 0x3F497DDACA41A95B
+ 7.32668430744625636189e-06, // 0x3EDEBAF7A5B38140
+}
+var _lgamS = [...]float64{
+ -7.72156649015328655494e-02, // 0xBFB3C467E37DB0C8
+ 2.14982415960608852501e-01, // 0x3FCB848B36E20878
+ 3.25778796408930981787e-01, // 0x3FD4D98F4F139F59
+ 1.46350472652464452805e-01, // 0x3FC2BB9CBEE5F2F7
+ 2.66422703033638609560e-02, // 0x3F9B481C7E939961
+ 1.84028451407337715652e-03, // 0x3F5E26B67368F239
+ 3.19475326584100867617e-05, // 0x3F00BFECDD17E945
+}
+var _lgamT = [...]float64{
+ 4.83836122723810047042e-01, // 0x3FDEF72BC8EE38A2
+ -1.47587722994593911752e-01, // 0xBFC2E4278DC6C509
+ 6.46249402391333854778e-02, // 0x3FB08B4294D5419B
+ -3.27885410759859649565e-02, // 0xBFA0C9A8DF35B713
+ 1.79706750811820387126e-02, // 0x3F9266E7970AF9EC
+ -1.03142241298341437450e-02, // 0xBF851F9FBA91EC6A
+ 6.10053870246291332635e-03, // 0x3F78FCE0E370E344
+ -3.68452016781138256760e-03, // 0xBF6E2EFFB3E914D7
+ 2.25964780900612472250e-03, // 0x3F6282D32E15C915
+ -1.40346469989232843813e-03, // 0xBF56FE8EBF2D1AF1
+ 8.81081882437654011382e-04, // 0x3F4CDF0CEF61A8E9
+ -5.38595305356740546715e-04, // 0xBF41A6109C73E0EC
+ 3.15632070903625950361e-04, // 0x3F34AF6D6C0EBBF7
+ -3.12754168375120860518e-04, // 0xBF347F24ECC38C38
+ 3.35529192635519073543e-04, // 0x3F35FD3EE8C2D3F4
+}
+var _lgamU = [...]float64{
+ -7.72156649015328655494e-02, // 0xBFB3C467E37DB0C8
+ 6.32827064025093366517e-01, // 0x3FE4401E8B005DFF
+ 1.45492250137234768737e+00, // 0x3FF7475CD119BD6F
+ 9.77717527963372745603e-01, // 0x3FEF497644EA8450
+ 2.28963728064692451092e-01, // 0x3FCD4EAEF6010924
+ 1.33810918536787660377e-02, // 0x3F8B678BBF2BAB09
+}
+var _lgamV = [...]float64{
+ 1.0,
+ 2.45597793713041134822e+00, // 0x4003A5D7C2BD619C
+ 2.12848976379893395361e+00, // 0x40010725A42B18F5
+ 7.69285150456672783825e-01, // 0x3FE89DFBE45050AF
+ 1.04222645593369134254e-01, // 0x3FBAAE55D6537C88
+ 3.21709242282423911810e-03, // 0x3F6A5ABB57D0CF61
+}
+var _lgamW = [...]float64{
+ 4.18938533204672725052e-01, // 0x3FDACFE390C97D69
+ 8.33333333333329678849e-02, // 0x3FB555555555553B
+ -2.77777777728775536470e-03, // 0xBF66C16C16B02E5C
+ 7.93650558643019558500e-04, // 0x3F4A019F98CF38B6
+ -5.95187557450339963135e-04, // 0xBF4380CB8C0FE741
+ 8.36339918996282139126e-04, // 0x3F4B67BA4CDAD5D1
+ -1.63092934096575273989e-03, // 0xBF5AB89D0B9E43E4
+}
+
// Lgamma returns the natural logarithm and sign (-1 or +1) of Gamma(x).
//
// Special cases are:
@@ -103,68 +178,10 @@ func Lgamma(x float64) (lgamma float64, sign int) {
Two53 = 1 << 53 // 0x4340000000000000 ~9.0072e+15
Two58 = 1 << 58 // 0x4390000000000000 ~2.8823e+17
Tiny = 1.0 / (1 << 70) // 0x3b90000000000000 ~8.47033e-22
- A0 = 7.72156649015328655494e-02 // 0x3FB3C467E37DB0C8
- A1 = 3.22467033424113591611e-01 // 0x3FD4A34CC4A60FAD
- A2 = 6.73523010531292681824e-02 // 0x3FB13E001A5562A7
- A3 = 2.05808084325167332806e-02 // 0x3F951322AC92547B
- A4 = 7.38555086081402883957e-03 // 0x3F7E404FB68FEFE8
- A5 = 2.89051383673415629091e-03 // 0x3F67ADD8CCB7926B
- A6 = 1.19270763183362067845e-03 // 0x3F538A94116F3F5D
- A7 = 5.10069792153511336608e-04 // 0x3F40B6C689B99C00
- A8 = 2.20862790713908385557e-04 // 0x3F2CF2ECED10E54D
- A9 = 1.08011567247583939954e-04 // 0x3F1C5088987DFB07
- A10 = 2.52144565451257326939e-05 // 0x3EFA7074428CFA52
- A11 = 4.48640949618915160150e-05 // 0x3F07858E90A45837
Tc = 1.46163214496836224576e+00 // 0x3FF762D86356BE3F
Tf = -1.21486290535849611461e-01 // 0xBFBF19B9BCC38A42
// Tt = -(tail of Tf)
- Tt = -3.63867699703950536541e-18 // 0xBC50C7CAA48A971F
- T0 = 4.83836122723810047042e-01 // 0x3FDEF72BC8EE38A2
- T1 = -1.47587722994593911752e-01 // 0xBFC2E4278DC6C509
- T2 = 6.46249402391333854778e-02 // 0x3FB08B4294D5419B
- T3 = -3.27885410759859649565e-02 // 0xBFA0C9A8DF35B713
- T4 = 1.79706750811820387126e-02 // 0x3F9266E7970AF9EC
- T5 = -1.03142241298341437450e-02 // 0xBF851F9FBA91EC6A
- T6 = 6.10053870246291332635e-03 // 0x3F78FCE0E370E344
- T7 = -3.68452016781138256760e-03 // 0xBF6E2EFFB3E914D7
- T8 = 2.25964780900612472250e-03 // 0x3F6282D32E15C915
- T9 = -1.40346469989232843813e-03 // 0xBF56FE8EBF2D1AF1
- T10 = 8.81081882437654011382e-04 // 0x3F4CDF0CEF61A8E9
- T11 = -5.38595305356740546715e-04 // 0xBF41A6109C73E0EC
- T12 = 3.15632070903625950361e-04 // 0x3F34AF6D6C0EBBF7
- T13 = -3.12754168375120860518e-04 // 0xBF347F24ECC38C38
- T14 = 3.35529192635519073543e-04 // 0x3F35FD3EE8C2D3F4
- U0 = -7.72156649015328655494e-02 // 0xBFB3C467E37DB0C8
- U1 = 6.32827064025093366517e-01 // 0x3FE4401E8B005DFF
- U2 = 1.45492250137234768737e+00 // 0x3FF7475CD119BD6F
- U3 = 9.77717527963372745603e-01 // 0x3FEF497644EA8450
- U4 = 2.28963728064692451092e-01 // 0x3FCD4EAEF6010924
- U5 = 1.33810918536787660377e-02 // 0x3F8B678BBF2BAB09
- V1 = 2.45597793713041134822e+00 // 0x4003A5D7C2BD619C
- V2 = 2.12848976379893395361e+00 // 0x40010725A42B18F5
- V3 = 7.69285150456672783825e-01 // 0x3FE89DFBE45050AF
- V4 = 1.04222645593369134254e-01 // 0x3FBAAE55D6537C88
- V5 = 3.21709242282423911810e-03 // 0x3F6A5ABB57D0CF61
- S0 = -7.72156649015328655494e-02 // 0xBFB3C467E37DB0C8
- S1 = 2.14982415960608852501e-01 // 0x3FCB848B36E20878
- S2 = 3.25778796408930981787e-01 // 0x3FD4D98F4F139F59
- S3 = 1.46350472652464452805e-01 // 0x3FC2BB9CBEE5F2F7
- S4 = 2.66422703033638609560e-02 // 0x3F9B481C7E939961
- S5 = 1.84028451407337715652e-03 // 0x3F5E26B67368F239
- S6 = 3.19475326584100867617e-05 // 0x3F00BFECDD17E945
- R1 = 1.39200533467621045958e+00 // 0x3FF645A762C4AB74
- R2 = 7.21935547567138069525e-01 // 0x3FE71A1893D3DCDC
- R3 = 1.71933865632803078993e-01 // 0x3FC601EDCCFBDF27
- R4 = 1.86459191715652901344e-02 // 0x3F9317EA742ED475
- R5 = 7.77942496381893596434e-04 // 0x3F497DDACA41A95B
- R6 = 7.32668430744625636189e-06 // 0x3EDEBAF7A5B38140
- W0 = 4.18938533204672725052e-01 // 0x3FDACFE390C97D69
- W1 = 8.33333333333329678849e-02 // 0x3FB555555555553B
- W2 = -2.77777777728775536470e-03 // 0xBF66C16C16B02E5C
- W3 = 7.93650558643019558500e-04 // 0x3F4A019F98CF38B6
- W4 = -5.95187557450339963135e-04 // 0xBF4380CB8C0FE741
- W5 = 8.36339918996282139126e-04 // 0x3F4B67BA4CDAD5D1
- W6 = -1.63092934096575273989e-03 // 0xBF5AB89D0B9E43E4
+ Tt = -3.63867699703950536541e-18 // 0xBC50C7CAA48A971F
)
// TODO(rsc): Remove manual inlining of IsNaN, IsInf
// when compiler does it for us
@@ -249,28 +266,28 @@ func Lgamma(x float64) (lgamma float64, sign int) {
switch i {
case 0:
z := y * y
- p1 := A0 + z*(A2+z*(A4+z*(A6+z*(A8+z*A10))))
- p2 := z * (A1 + z*(A3+z*(A5+z*(A7+z*(A9+z*A11)))))
+ p1 := _lgamA[0] + z*(_lgamA[2]+z*(_lgamA[4]+z*(_lgamA[6]+z*(_lgamA[8]+z*_lgamA[10]))))
+ p2 := z * (_lgamA[1] + z*(+_lgamA[3]+z*(_lgamA[5]+z*(_lgamA[7]+z*(_lgamA[9]+z*_lgamA[11])))))
p := y*p1 + p2
lgamma += (p - 0.5*y)
case 1:
z := y * y
w := z * y
- p1 := T0 + w*(T3+w*(T6+w*(T9+w*T12))) // parallel comp
- p2 := T1 + w*(T4+w*(T7+w*(T10+w*T13)))
- p3 := T2 + w*(T5+w*(T8+w*(T11+w*T14)))
+ p1 := _lgamT[0] + w*(_lgamT[3]+w*(_lgamT[6]+w*(_lgamT[9]+w*_lgamT[12]))) // parallel comp
+ p2 := _lgamT[1] + w*(_lgamT[4]+w*(_lgamT[7]+w*(_lgamT[10]+w*_lgamT[13])))
+ p3 := _lgamT[2] + w*(_lgamT[5]+w*(_lgamT[8]+w*(_lgamT[11]+w*_lgamT[14])))
p := z*p1 - (Tt - w*(p2+y*p3))
lgamma += (Tf + p)
case 2:
- p1 := y * (U0 + y*(U1+y*(U2+y*(U3+y*(U4+y*U5)))))
- p2 := 1 + y*(V1+y*(V2+y*(V3+y*(V4+y*V5))))
+ p1 := y * (_lgamU[0] + y*(_lgamU[1]+y*(_lgamU[2]+y*(_lgamU[3]+y*(_lgamU[4]+y*_lgamU[5])))))
+ p2 := 1 + y*(_lgamV[1]+y*(_lgamV[2]+y*(_lgamV[3]+y*(_lgamV[4]+y*_lgamV[5]))))
lgamma += (-0.5*y + p1/p2)
}
case x < 8: // 2 <= x < 8
i := int(x)
y := x - float64(i)
- p := y * (S0 + y*(S1+y*(S2+y*(S3+y*(S4+y*(S5+y*S6))))))
- q := 1 + y*(R1+y*(R2+y*(R3+y*(R4+y*(R5+y*R6)))))
+ p := y * (_lgamS[0] + y*(_lgamS[1]+y*(_lgamS[2]+y*(_lgamS[3]+y*(_lgamS[4]+y*(_lgamS[5]+y*_lgamS[6]))))))
+ q := 1 + y*(_lgamR[1]+y*(_lgamR[2]+y*(_lgamR[3]+y*(_lgamR[4]+y*(_lgamR[5]+y*_lgamR[6])))))
lgamma = 0.5*y + p/q
z := 1.0 // Lgamma(1+s) = Log(s) + Lgamma(s)
switch i {
@@ -294,7 +311,7 @@ func Lgamma(x float64) (lgamma float64, sign int) {
t := Log(x)
z := 1 / x
y := z * z
- w := W0 + z*(W1+y*(W2+y*(W3+y*(W4+y*(W5+y*W6)))))
+ w := _lgamW[0] + z*(_lgamW[1]+y*(_lgamW[2]+y*(_lgamW[3]+y*(_lgamW[4]+y*(_lgamW[5]+y*_lgamW[6])))))
lgamma = (x-0.5)*(t-1) + w
default: // 2**58 <= x <= Inf
lgamma = x * (Log(x) - 1)
diff --git a/libgo/go/mime/multipart/formdata.go b/libgo/go/mime/multipart/formdata.go
index d9982e5b9c8..ec643c1476f 100644
--- a/libgo/go/mime/multipart/formdata.go
+++ b/libgo/go/mime/multipart/formdata.go
@@ -160,7 +160,7 @@ type sliceReaderAt []byte
func (r sliceReaderAt) ReadAt(b []byte, off int64) (int, error) {
if int(off) >= len(r) || off < 0 {
- return 0, os.EINVAL
+ return 0, io.ErrUnexpectedEOF
}
n := copy(b, r[int(off):])
return n, nil
diff --git a/libgo/go/mime/type.go b/libgo/go/mime/type.go
index ce72bb5f7f9..e3d968fb81a 100644
--- a/libgo/go/mime/type.go
+++ b/libgo/go/mime/type.go
@@ -6,19 +6,11 @@
package mime
import (
- "bufio"
"fmt"
- "os"
"strings"
"sync"
)
-var typeFiles = []string{
- "/etc/mime.types",
- "/etc/apache2/mime.types",
- "/etc/apache/mime.types",
-}
-
var mimeTypes = map[string]string{
".css": "text/css; charset=utf-8",
".gif": "image/gif",
@@ -33,46 +25,13 @@ var mimeTypes = map[string]string{
var mimeLock sync.RWMutex
-func loadMimeFile(filename string) {
- f, err := os.Open(filename)
- if err != nil {
- return
- }
-
- reader := bufio.NewReader(f)
- for {
- line, err := reader.ReadString('\n')
- if err != nil {
- f.Close()
- return
- }
- fields := strings.Fields(line)
- if len(fields) <= 1 || fields[0][0] == '#' {
- continue
- }
- mimeType := fields[0]
- for _, ext := range fields[1:] {
- if ext[0] == '#' {
- break
- }
- setExtensionType("."+ext, mimeType)
- }
- }
-}
-
-func initMime() {
- for _, filename := range typeFiles {
- loadMimeFile(filename)
- }
-}
-
var once sync.Once
// TypeByExtension returns the MIME type associated with the file extension ext.
// The extension ext should begin with a leading dot, as in ".html".
// When ext has no associated type, TypeByExtension returns "".
//
-// The built-in table is small but is is augmented by the local
+// The built-in table is small but on unix it is augmented by the local
// system's mime.types file(s) if available under one or more of these
// names:
//
@@ -80,6 +39,8 @@ var once sync.Once
// /etc/apache2/mime.types
// /etc/apache/mime.types
//
+// Windows system mime types are extracted from registry.
+//
// Text types have the charset parameter set to "utf-8" by default.
func TypeByExtension(ext string) string {
once.Do(initMime)
diff --git a/libgo/go/mime/type_test.go b/libgo/go/mime/type_test.go
index 976f8534309..07e1cd5daec 100644
--- a/libgo/go/mime/type_test.go
+++ b/libgo/go/mime/type_test.go
@@ -6,15 +6,9 @@ package mime
import "testing"
-var typeTests = map[string]string{
- ".t1": "application/test",
- ".t2": "text/test; charset=utf-8",
- ".png": "image/png",
-}
+var typeTests = initMimeForTests()
func TestTypeByExtension(t *testing.T) {
- typeFiles = []string{"test.types"}
-
for ext, want := range typeTests {
val := TypeByExtension(ext)
if val != want {
diff --git a/libgo/go/mime/type_unix.go b/libgo/go/mime/type_unix.go
new file mode 100644
index 00000000000..45127ba29df
--- /dev/null
+++ b/libgo/go/mime/type_unix.go
@@ -0,0 +1,59 @@
+// Copyright 2010 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 mime
+
+import (
+ "bufio"
+ "os"
+ "strings"
+)
+
+var typeFiles = []string{
+ "/etc/mime.types",
+ "/etc/apache2/mime.types",
+ "/etc/apache/mime.types",
+}
+
+func loadMimeFile(filename string) {
+ f, err := os.Open(filename)
+ if err != nil {
+ return
+ }
+
+ reader := bufio.NewReader(f)
+ for {
+ line, err := reader.ReadString('\n')
+ if err != nil {
+ f.Close()
+ return
+ }
+ fields := strings.Fields(line)
+ if len(fields) <= 1 || fields[0][0] == '#' {
+ continue
+ }
+ mimeType := fields[0]
+ for _, ext := range fields[1:] {
+ if ext[0] == '#' {
+ break
+ }
+ setExtensionType("."+ext, mimeType)
+ }
+ }
+}
+
+func initMime() {
+ for _, filename := range typeFiles {
+ loadMimeFile(filename)
+ }
+}
+
+func initMimeForTests() map[string]string {
+ typeFiles = []string{"test.types"}
+ return map[string]string{
+ ".t1": "application/test",
+ ".t2": "text/test; charset=utf-8",
+ ".png": "image/png",
+ }
+}
diff --git a/libgo/go/mime/type_windows.go b/libgo/go/mime/type_windows.go
new file mode 100644
index 00000000000..7cf2d3984b1
--- /dev/null
+++ b/libgo/go/mime/type_windows.go
@@ -0,0 +1,61 @@
+// Copyright 2010 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 mime
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+func initMime() {
+ var root syscall.Handle
+ if syscall.RegOpenKeyEx(syscall.HKEY_CLASSES_ROOT, syscall.StringToUTF16Ptr(`\`),
+ 0, syscall.KEY_READ, &root) != 0 {
+ return
+ }
+ defer syscall.RegCloseKey(root)
+ var count uint32
+ if syscall.RegQueryInfoKey(root, nil, nil, nil, &count, nil, nil, nil, nil, nil, nil, nil) != 0 {
+ return
+ }
+ var buf [1 << 10]uint16
+ for i := uint32(0); i < count; i++ {
+ n := uint32(len(buf))
+ if syscall.RegEnumKeyEx(root, i, &buf[0], &n, nil, nil, nil, nil) != 0 {
+ continue
+ }
+ ext := syscall.UTF16ToString(buf[:])
+ if len(ext) < 2 || ext[0] != '.' { // looking for extensions only
+ continue
+ }
+ var h syscall.Handle
+ if syscall.RegOpenKeyEx(
+ syscall.HKEY_CLASSES_ROOT, syscall.StringToUTF16Ptr(`\`+ext),
+ 0, syscall.KEY_READ, &h) != 0 {
+ continue
+ }
+ var typ uint32
+ n = uint32(len(buf) * 2) // api expects array of bytes, not uint16
+ if syscall.RegQueryValueEx(
+ h, syscall.StringToUTF16Ptr("Content Type"),
+ nil, &typ, (*byte)(unsafe.Pointer(&buf[0])), &n) != 0 {
+ syscall.RegCloseKey(h)
+ continue
+ }
+ syscall.RegCloseKey(h)
+ if typ != syscall.REG_SZ { // null terminated strings only
+ continue
+ }
+ mimeType := syscall.UTF16ToString(buf[:])
+ setExtensionType(ext, mimeType)
+ }
+}
+
+func initMimeForTests() map[string]string {
+ return map[string]string{
+ ".bmp": "image/bmp",
+ ".png": "image/png",
+ }
+}
diff --git a/libgo/go/net/cgo_unix.go b/libgo/go/net/cgo_unix.go
index 680d3e70b11..1a0f4063c5a 100644
--- a/libgo/go/net/cgo_unix.go
+++ b/libgo/go/net/cgo_unix.go
@@ -109,7 +109,7 @@ func cgoLookupIPCNAME(name string) (addrs []IP, cname string, err error, complet
if gerrno == syscall.EAI_NONAME {
str = noSuchHost
} else if gerrno == syscall.EAI_SYSTEM {
- str = syscall.Errstr(syscall.GetErrno())
+ str = syscall.GetErrno().Error()
} else {
str = bytePtrToString(libc_gai_strerror(gerrno))
}
diff --git a/libgo/go/net/fd.go b/libgo/go/net/fd.go
index 025075de48f..70e04a21c0b 100644
--- a/libgo/go/net/fd.go
+++ b/libgo/go/net/fd.go
@@ -278,8 +278,8 @@ func startServer() {
func newFD(fd, family, proto int, net string) (f *netFD, err error) {
onceStartServer.Do(startServer)
- if e := syscall.SetNonblock(fd, true); e != 0 {
- return nil, os.Errno(e)
+ if e := syscall.SetNonblock(fd, true); e != nil {
+ return nil, e
}
f = &netFD{
sysfd: fd,
@@ -306,19 +306,19 @@ func (fd *netFD) setAddr(laddr, raddr Addr) {
}
func (fd *netFD) connect(ra syscall.Sockaddr) (err error) {
- e := syscall.Connect(fd.sysfd, ra)
- if e == syscall.EINPROGRESS {
- var errno int
+ err = syscall.Connect(fd.sysfd, ra)
+ if err == syscall.EINPROGRESS {
pollserver.WaitWrite(fd)
- e, errno = syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
- if errno != 0 {
- return os.NewSyscallError("getsockopt", errno)
+ var e int
+ e, err = syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
+ if err != nil {
+ return os.NewSyscallError("getsockopt", err)
+ }
+ if e != 0 {
+ err = syscall.Errno(e)
}
}
- if e != 0 {
- return os.Errno(e)
- }
- return nil
+ return err
}
// Add a reference to this fd.
@@ -362,9 +362,9 @@ func (fd *netFD) shutdown(how int) error {
if fd == nil || fd.sysfile == nil {
return os.EINVAL
}
- errno := syscall.Shutdown(fd.sysfd, how)
- if errno != 0 {
- return &OpError{"shutdown", fd.net, fd.laddr, os.Errno(errno)}
+ err := syscall.Shutdown(fd.sysfd, how)
+ if err != nil {
+ return &OpError{"shutdown", fd.net, fd.laddr, err}
}
return nil
}
@@ -377,6 +377,14 @@ func (fd *netFD) CloseWrite() error {
return fd.shutdown(syscall.SHUT_WR)
}
+type timeoutError struct{}
+
+func (e *timeoutError) Error() string { return "i/o timeout" }
+func (e *timeoutError) Timeout() bool { return true }
+func (e *timeoutError) Temporary() bool { return true }
+
+var errTimeout error = &timeoutError{}
+
func (fd *netFD) Read(p []byte) (n int, err error) {
if fd == nil {
return 0, os.EINVAL
@@ -393,24 +401,24 @@ func (fd *netFD) Read(p []byte) (n int, err error) {
} else {
fd.rdeadline = 0
}
- var oserr error
for {
- var errno int
- n, errno = syscall.Read(fd.sysfile.Fd(), p)
- if errno == syscall.EAGAIN && fd.rdeadline >= 0 {
- pollserver.WaitRead(fd)
- continue
+ n, err = syscall.Read(fd.sysfile.Fd(), p)
+ if err == syscall.EAGAIN {
+ if fd.rdeadline >= 0 {
+ pollserver.WaitRead(fd)
+ continue
+ }
+ err = errTimeout
}
- if errno != 0 {
+ if err != nil {
n = 0
- oserr = os.Errno(errno)
- } else if n == 0 && errno == 0 && fd.proto != syscall.SOCK_DGRAM {
+ } else if n == 0 && err == nil && fd.proto != syscall.SOCK_DGRAM {
err = io.EOF
}
break
}
- if oserr != nil {
- err = &OpError{"read", fd.net, fd.raddr, oserr}
+ if err != nil && err != io.EOF {
+ err = &OpError{"read", fd.net, fd.raddr, err}
}
return
}
@@ -428,22 +436,22 @@ func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
} else {
fd.rdeadline = 0
}
- var oserr error
for {
- var errno int
- n, sa, errno = syscall.Recvfrom(fd.sysfd, p, 0)
- if errno == syscall.EAGAIN && fd.rdeadline >= 0 {
- pollserver.WaitRead(fd)
- continue
+ n, sa, err = syscall.Recvfrom(fd.sysfd, p, 0)
+ if err == syscall.EAGAIN {
+ if fd.rdeadline >= 0 {
+ pollserver.WaitRead(fd)
+ continue
+ }
+ err = errTimeout
}
- if errno != 0 {
+ if err != nil {
n = 0
- oserr = os.Errno(errno)
}
break
}
- if oserr != nil {
- err = &OpError{"read", fd.net, fd.laddr, oserr}
+ if err != nil {
+ err = &OpError{"read", fd.net, fd.laddr, err}
}
return
}
@@ -461,24 +469,22 @@ func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.S
} else {
fd.rdeadline = 0
}
- var oserr error
for {
- var errno int
- n, oobn, flags, sa, errno = syscall.Recvmsg(fd.sysfd, p, oob, 0)
- if errno == syscall.EAGAIN && fd.rdeadline >= 0 {
- pollserver.WaitRead(fd)
- continue
- }
- if errno != 0 {
- oserr = os.Errno(errno)
+ n, oobn, flags, sa, err = syscall.Recvmsg(fd.sysfd, p, oob, 0)
+ if err == syscall.EAGAIN {
+ if fd.rdeadline >= 0 {
+ pollserver.WaitRead(fd)
+ continue
+ }
+ err = errTimeout
}
- if n == 0 {
- oserr = io.EOF
+ if err == nil && n == 0 {
+ err = io.EOF
}
break
}
- if oserr != nil {
- err = &OpError{"read", fd.net, fd.laddr, oserr}
+ if err != nil && err != io.EOF {
+ err = &OpError{"read", fd.net, fd.laddr, err}
return
}
return
@@ -501,32 +507,34 @@ func (fd *netFD) Write(p []byte) (n int, err error) {
fd.wdeadline = 0
}
nn := 0
- var oserr error
for {
- n, errno := syscall.Write(fd.sysfile.Fd(), p[nn:])
+ var n int
+ n, err = syscall.Write(fd.sysfile.Fd(), p[nn:])
if n > 0 {
nn += n
}
if nn == len(p) {
break
}
- if errno == syscall.EAGAIN && fd.wdeadline >= 0 {
- pollserver.WaitWrite(fd)
- continue
+ if err == syscall.EAGAIN {
+ if fd.wdeadline >= 0 {
+ pollserver.WaitWrite(fd)
+ continue
+ }
+ err = errTimeout
}
- if errno != 0 {
+ if err != nil {
n = 0
- oserr = os.Errno(errno)
break
}
if n == 0 {
- oserr = io.ErrUnexpectedEOF
+ err = io.ErrUnexpectedEOF
break
}
}
- if oserr != nil {
- err = &OpError{"write", fd.net, fd.raddr, oserr}
+ if err != nil {
+ err = &OpError{"write", fd.net, fd.raddr, err}
}
return nn, err
}
@@ -544,22 +552,21 @@ func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
} else {
fd.wdeadline = 0
}
- var oserr error
for {
- errno := syscall.Sendto(fd.sysfd, p, 0, sa)
- if errno == syscall.EAGAIN && fd.wdeadline >= 0 {
- pollserver.WaitWrite(fd)
- continue
- }
- if errno != 0 {
- oserr = os.Errno(errno)
+ err = syscall.Sendto(fd.sysfd, p, 0, sa)
+ if err == syscall.EAGAIN {
+ if fd.wdeadline >= 0 {
+ pollserver.WaitWrite(fd)
+ continue
+ }
+ err = errTimeout
}
break
}
- if oserr == nil {
+ if err == nil {
n = len(p)
} else {
- err = &OpError{"write", fd.net, fd.raddr, oserr}
+ err = &OpError{"write", fd.net, fd.raddr, err}
}
return
}
@@ -577,24 +584,22 @@ func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oob
} else {
fd.wdeadline = 0
}
- var oserr error
for {
- var errno int
- errno = syscall.Sendmsg(fd.sysfd, p, oob, sa, 0)
- if errno == syscall.EAGAIN && fd.wdeadline >= 0 {
- pollserver.WaitWrite(fd)
- continue
- }
- if errno != 0 {
- oserr = os.Errno(errno)
+ err = syscall.Sendmsg(fd.sysfd, p, oob, sa, 0)
+ if err == syscall.EAGAIN {
+ if fd.wdeadline >= 0 {
+ pollserver.WaitWrite(fd)
+ continue
+ }
+ err = errTimeout
}
break
}
- if oserr == nil {
+ if err == nil {
n = len(p)
oobn = len(oob)
} else {
- err = &OpError{"write", fd.net, fd.raddr, oserr}
+ err = &OpError{"write", fd.net, fd.raddr, err}
}
return
}
@@ -615,25 +620,26 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err err
// See ../syscall/exec.go for description of ForkLock.
// It is okay to hold the lock across syscall.Accept
// because we have put fd.sysfd into non-blocking mode.
- syscall.ForkLock.RLock()
- var s, e int
+ var s int
var rsa syscall.Sockaddr
for {
if fd.closing {
- syscall.ForkLock.RUnlock()
return nil, os.EINVAL
}
- s, rsa, e = syscall.Accept(fd.sysfd)
- if e != syscall.EAGAIN || fd.rdeadline < 0 {
- break
- }
- syscall.ForkLock.RUnlock()
- pollserver.WaitRead(fd)
syscall.ForkLock.RLock()
- }
- if e != 0 {
- syscall.ForkLock.RUnlock()
- return nil, &OpError{"accept", fd.net, fd.laddr, os.Errno(e)}
+ s, rsa, err = syscall.Accept(fd.sysfd)
+ if err != nil {
+ syscall.ForkLock.RUnlock()
+ if err == syscall.EAGAIN {
+ if fd.rdeadline >= 0 {
+ pollserver.WaitRead(fd)
+ continue
+ }
+ err = errTimeout
+ }
+ return nil, &OpError{"accept", fd.net, fd.laddr, err}
+ }
+ break
}
syscall.CloseOnExec(s)
syscall.ForkLock.RUnlock()
@@ -648,19 +654,19 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err err
}
func (fd *netFD) dup() (f *os.File, err error) {
- ns, e := syscall.Dup(fd.sysfd)
- if e != 0 {
- return nil, &OpError{"dup", fd.net, fd.laddr, os.Errno(e)}
+ ns, err := syscall.Dup(fd.sysfd)
+ if err != nil {
+ return nil, &OpError{"dup", fd.net, fd.laddr, err}
}
// We want blocking mode for the new fd, hence the double negative.
- if e = syscall.SetNonblock(ns, false); e != 0 {
- return nil, &OpError{"setnonblock", fd.net, fd.laddr, os.Errno(e)}
+ if err = syscall.SetNonblock(ns, false); err != nil {
+ return nil, &OpError{"setnonblock", fd.net, fd.laddr, err}
}
return os.NewFile(ns, fd.sysfile.Name()), nil
}
-func closesocket(s int) (errno int) {
+func closesocket(s int) error {
return syscall.Close(s)
}
diff --git a/libgo/go/net/fd_linux.go b/libgo/go/net/fd_linux.go
index cce74cd6760..8e07833882e 100644
--- a/libgo/go/net/fd_linux.go
+++ b/libgo/go/net/fd_linux.go
@@ -35,12 +35,12 @@ type pollster struct {
func newpollster() (p *pollster, err error) {
p = new(pollster)
- var e int
+ var e error
// The arg to epoll_create is a hint to the kernel
// about the number of FDs we will care about.
// We don't know, and since 2.6.8 the kernel ignores it anyhow.
- if p.epfd, e = syscall.EpollCreate(16); e != 0 {
+ if p.epfd, e = syscall.EpollCreate(16); e != nil {
return nil, os.NewSyscallError("epoll_create", e)
}
p.events = make(map[int]uint32)
@@ -68,7 +68,7 @@ func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, error) {
} else {
op = syscall.EPOLL_CTL_ADD
}
- if e := syscall.EpollCtl(p.epfd, op, fd, &p.ctlEvent); e != 0 {
+ if e := syscall.EpollCtl(p.epfd, op, fd, &p.ctlEvent); e != nil {
return false, os.NewSyscallError("epoll_ctl", e)
}
p.events[fd] = p.ctlEvent.Events
@@ -97,13 +97,13 @@ func (p *pollster) StopWaiting(fd int, bits uint) {
if int32(events)&^syscall.EPOLLONESHOT != 0 {
p.ctlEvent.Fd = int32(fd)
p.ctlEvent.Events = events
- if e := syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_MOD, fd, &p.ctlEvent); e != 0 {
- print("Epoll modify fd=", fd, ": ", os.Errno(e).Error(), "\n")
+ if e := syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_MOD, fd, &p.ctlEvent); e != nil {
+ print("Epoll modify fd=", fd, ": ", e.Error(), "\n")
}
p.events[fd] = events
} else {
- if e := syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_DEL, fd, nil); e != 0 {
- print("Epoll delete fd=", fd, ": ", os.Errno(e).Error(), "\n")
+ if e := syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_DEL, fd, nil); e != nil {
+ print("Epoll delete fd=", fd, ": ", e.Error(), "\n")
}
delete(p.events, fd)
}
@@ -141,7 +141,7 @@ func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err erro
n, e := syscall.EpollWait(p.epfd, p.waitEventBuf[0:], msec)
s.Lock()
- if e != 0 {
+ if e != nil {
if e == syscall.EAGAIN || e == syscall.EINTR {
continue
}
diff --git a/libgo/go/net/fd_openbsd.go b/libgo/go/net/fd_openbsd.go
index f61008a2fe1..e52ac356b9f 100644
--- a/libgo/go/net/fd_openbsd.go
+++ b/libgo/go/net/fd_openbsd.go
@@ -23,9 +23,8 @@ type pollster struct {
func newpollster() (p *pollster, err error) {
p = new(pollster)
- var e int
- if p.kq, e = syscall.Kqueue(); e != 0 {
- return nil, os.NewSyscallError("kqueue", e)
+ if p.kq, err = syscall.Kqueue(); err != nil {
+ return nil, os.NewSyscallError("kqueue", err)
}
p.events = p.eventbuf[0:0]
return p, nil
@@ -50,14 +49,14 @@ func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, error) {
syscall.SetKevent(ev, fd, kmode, flags)
n, e := syscall.Kevent(p.kq, p.kbuf[:], nil, nil)
- if e != 0 {
+ if e != nil {
return false, os.NewSyscallError("kevent", e)
}
if n != 1 || (ev.Flags&syscall.EV_ERROR) == 0 || int(ev.Ident) != fd || int(ev.Filter) != kmode {
return false, os.NewSyscallError("kqueue phase error", e)
}
if ev.Data != 0 {
- return false, os.Errno(int(ev.Data))
+ return false, syscall.Errno(int(ev.Data))
}
return false, nil
}
@@ -91,7 +90,7 @@ func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err erro
nn, e := syscall.Kevent(p.kq, nil, p.eventbuf[:], t)
s.Lock()
- if e != 0 {
+ if e != nil {
if e == syscall.EINTR {
continue
}
diff --git a/libgo/go/net/fd_windows.go b/libgo/go/net/fd_windows.go
index ce228e91edb..7a1602371e9 100644
--- a/libgo/go/net/fd_windows.go
+++ b/libgo/go/net/fd_windows.go
@@ -26,11 +26,11 @@ func init() {
var d syscall.WSAData
e := syscall.WSAStartup(uint32(0x202), &d)
if e != 0 {
- initErr = os.NewSyscallError("WSAStartup", e)
+ initErr = os.NewSyscallError("WSAStartup", syscall.Errno(e))
}
}
-func closesocket(s syscall.Handle) (errno int) {
+func closesocket(s syscall.Handle) (err error) {
return syscall.Closesocket(s)
}
@@ -38,13 +38,13 @@ func closesocket(s syscall.Handle) (errno int) {
type anOpIface interface {
Op() *anOp
Name() string
- Submit() (errno int)
+ Submit() (err error)
}
// IO completion result parameters.
type ioResult struct {
qty uint32
- err int
+ err error
}
// anOp implements functionality common to all io operations.
@@ -54,7 +54,7 @@ type anOp struct {
o syscall.Overlapped
resultc chan ioResult
- errnoc chan int
+ errnoc chan error
fd *netFD
}
@@ -71,7 +71,7 @@ func (o *anOp) Init(fd *netFD, mode int) {
}
o.resultc = fd.resultc[i]
if fd.errnoc[i] == nil {
- fd.errnoc[i] = make(chan int)
+ fd.errnoc[i] = make(chan error)
}
o.errnoc = fd.errnoc[i]
}
@@ -111,14 +111,14 @@ func (s *resultSrv) Run() {
for {
r.err = syscall.GetQueuedCompletionStatus(s.iocp, &(r.qty), &key, &o, syscall.INFINITE)
switch {
- case r.err == 0:
+ case r.err == nil:
// Dequeued successfully completed io packet.
- case r.err == syscall.WAIT_TIMEOUT && o == nil:
+ case r.err == syscall.Errno(syscall.WAIT_TIMEOUT) && o == nil:
// Wait has timed out (should not happen now, but might be used in the future).
panic("GetQueuedCompletionStatus timed out")
case o == nil:
// Failed to dequeue anything -> report the error.
- panic("GetQueuedCompletionStatus failed " + syscall.Errstr(r.err))
+ panic("GetQueuedCompletionStatus failed " + r.err.Error())
default:
// Dequeued failed io packet.
}
@@ -153,7 +153,7 @@ func (s *ioSrv) ProcessRemoteIO() {
// inline, or, if timeouts are employed, passes the request onto
// a special goroutine and waits for completion or cancels request.
func (s *ioSrv) ExecIO(oi anOpIface, deadline_delta int64) (n int, err error) {
- var e int
+ var e error
o := oi.Op()
if deadline_delta > 0 {
// Send request to a special dedicated thread,
@@ -164,12 +164,12 @@ func (s *ioSrv) ExecIO(oi anOpIface, deadline_delta int64) (n int, err error) {
e = oi.Submit()
}
switch e {
- case 0:
+ case nil:
// IO completed immediately, but we need to get our completion message anyway.
case syscall.ERROR_IO_PENDING:
// IO started, and we have to wait for its completion.
default:
- return 0, &OpError{oi.Name(), o.fd.net, o.fd.laddr, os.Errno(e)}
+ return 0, &OpError{oi.Name(), o.fd.net, o.fd.laddr, e}
}
// Wait for our request to complete.
var r ioResult
@@ -187,8 +187,8 @@ func (s *ioSrv) ExecIO(oi anOpIface, deadline_delta int64) (n int, err error) {
} else {
r = <-o.resultc
}
- if r.err != 0 {
- err = &OpError{oi.Name(), o.fd.net, o.fd.laddr, os.Errno(r.err)}
+ if r.err != nil {
+ err = &OpError{oi.Name(), o.fd.net, o.fd.laddr, r.err}
}
return int(r.qty), err
}
@@ -200,10 +200,10 @@ var onceStartServer sync.Once
func startServer() {
resultsrv = new(resultSrv)
- var errno int
- resultsrv.iocp, errno = syscall.CreateIoCompletionPort(syscall.InvalidHandle, 0, 0, 1)
- if errno != 0 {
- panic("CreateIoCompletionPort failed " + syscall.Errstr(errno))
+ var err error
+ resultsrv.iocp, err = syscall.CreateIoCompletionPort(syscall.InvalidHandle, 0, 0, 1)
+ if err != nil {
+ panic("CreateIoCompletionPort: " + err.Error())
}
go resultsrv.Run()
@@ -228,7 +228,7 @@ type netFD struct {
laddr Addr
raddr Addr
resultc [2]chan ioResult // read/write completion results
- errnoc [2]chan int // read/write submit or cancel operation errors
+ errnoc [2]chan error // read/write submit or cancel operation errors
// owned by client
rdeadline_delta int64
@@ -256,8 +256,8 @@ func newFD(fd syscall.Handle, family, proto int, net string) (f *netFD, err erro
}
onceStartServer.Do(startServer)
// Associate our socket with resultsrv.iocp.
- if _, e := syscall.CreateIoCompletionPort(syscall.Handle(fd), resultsrv.iocp, 0, 0); e != 0 {
- return nil, os.Errno(e)
+ if _, e := syscall.CreateIoCompletionPort(syscall.Handle(fd), resultsrv.iocp, 0, 0); e != nil {
+ return nil, e
}
return allocFD(fd, family, proto, net), nil
}
@@ -268,11 +268,7 @@ func (fd *netFD) setAddr(laddr, raddr Addr) {
}
func (fd *netFD) connect(ra syscall.Sockaddr) (err error) {
- e := syscall.Connect(fd.sysfd, ra)
- if e != 0 {
- return os.Errno(e)
- }
- return nil
+ return syscall.Connect(fd.sysfd, ra)
}
// Add a reference to this fd.
@@ -317,9 +313,9 @@ func (fd *netFD) shutdown(how int) error {
if fd == nil || fd.sysfd == syscall.InvalidHandle {
return os.EINVAL
}
- errno := syscall.Shutdown(fd.sysfd, how)
- if errno != 0 {
- return &OpError{"shutdown", fd.net, fd.laddr, os.Errno(errno)}
+ err := syscall.Shutdown(fd.sysfd, how)
+ if err != nil {
+ return &OpError{"shutdown", fd.net, fd.laddr, err}
}
return nil
}
@@ -338,7 +334,7 @@ type readOp struct {
bufOp
}
-func (o *readOp) Submit() (errno int) {
+func (o *readOp) Submit() (err error) {
var d, f uint32
return syscall.WSARecv(syscall.Handle(o.fd.sysfd), &o.buf, 1, &d, &f, &o.o, nil)
}
@@ -375,7 +371,7 @@ type readFromOp struct {
rsan int32
}
-func (o *readFromOp) Submit() (errno int) {
+func (o *readFromOp) Submit() (err error) {
var d, f uint32
return syscall.WSARecvFrom(o.fd.sysfd, &o.buf, 1, &d, &f, &o.rsa, &o.rsan, &o.o, nil)
}
@@ -415,7 +411,7 @@ type writeOp struct {
bufOp
}
-func (o *writeOp) Submit() (errno int) {
+func (o *writeOp) Submit() (err error) {
var d uint32
return syscall.WSASend(o.fd.sysfd, &o.buf, 1, &d, 0, &o.o, nil)
}
@@ -447,7 +443,7 @@ type writeToOp struct {
sa syscall.Sockaddr
}
-func (o *writeToOp) Submit() (errno int) {
+func (o *writeToOp) Submit() (err error) {
var d uint32
return syscall.WSASendto(o.fd.sysfd, &o.buf, 1, &d, 0, o.sa, &o.o, nil)
}
@@ -484,7 +480,7 @@ type acceptOp struct {
attrs [2]syscall.RawSockaddrAny // space for local and remote address only
}
-func (o *acceptOp) Submit() (errno int) {
+func (o *acceptOp) Submit() (err error) {
var d uint32
l := uint32(unsafe.Sizeof(o.attrs[0]))
return syscall.AcceptEx(o.fd.sysfd, o.newsock,
@@ -506,17 +502,17 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err err
// See ../syscall/exec.go for description of ForkLock.
syscall.ForkLock.RLock()
s, e := syscall.Socket(fd.family, fd.proto, 0)
- if e != 0 {
+ if e != nil {
syscall.ForkLock.RUnlock()
- return nil, os.Errno(e)
+ return nil, e
}
syscall.CloseOnExec(s)
syscall.ForkLock.RUnlock()
// Associate our new socket with IOCP.
onceStartServer.Do(startServer)
- if _, e = syscall.CreateIoCompletionPort(s, resultsrv.iocp, 0, 0); e != 0 {
- return nil, &OpError{"CreateIoCompletionPort", fd.net, fd.laddr, os.Errno(e)}
+ if _, e = syscall.CreateIoCompletionPort(s, resultsrv.iocp, 0, 0); e != nil {
+ return nil, &OpError{"CreateIoCompletionPort", fd.net, fd.laddr, e}
}
// Submit accept request.
@@ -531,9 +527,9 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err err
// Inherit properties of the listening socket.
e = syscall.Setsockopt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd)))
- if e != 0 {
+ if e != nil {
closesocket(s)
- return nil, err
+ return nil, e
}
// Get local and peer addr out of AcceptEx buffer.
diff --git a/libgo/go/net/file.go b/libgo/go/net/file.go
index 0ad869dbd57..bf8cd9dae04 100644
--- a/libgo/go/net/file.go
+++ b/libgo/go/net/file.go
@@ -13,12 +13,12 @@ import (
func newFileFD(f *os.File) (nfd *netFD, err error) {
fd, errno := syscall.Dup(f.Fd())
- if errno != 0 {
+ if errno != nil {
return nil, os.NewSyscallError("dup", errno)
}
proto, errno := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_TYPE)
- if errno != 0 {
+ if errno != nil {
return nil, os.NewSyscallError("getsockopt", errno)
}
diff --git a/libgo/go/net/hosts.go b/libgo/go/net/hosts.go
index d75e9e038a6..ddfb074ee8f 100644
--- a/libgo/go/net/hosts.go
+++ b/libgo/go/net/hosts.go
@@ -7,8 +7,8 @@
package net
import (
- "os"
"sync"
+ "time"
)
const cacheMaxAge = int64(300) // 5 minutes.
@@ -26,7 +26,7 @@ var hosts struct {
}
func readHosts() {
- now, _, _ := os.Time()
+ now := time.Seconds()
hp := hostsPath
if len(hosts.byName) == 0 || hosts.time+cacheMaxAge <= now || hosts.path != hp {
hs := make(map[string][]string)
@@ -51,7 +51,7 @@ func readHosts() {
}
}
// Update the data cache.
- hosts.time, _, _ = os.Time()
+ hosts.time = time.Seconds()
hosts.path = hp
hosts.byName = hs
hosts.byAddr = is
diff --git a/libgo/go/net/http/cgi/host_test.go b/libgo/go/net/http/cgi/host_test.go
index 2bc913a1696..e6e85e8db3b 100644
--- a/libgo/go/net/http/cgi/host_test.go
+++ b/libgo/go/net/http/cgi/host_test.go
@@ -363,14 +363,13 @@ func TestCopyError(t *testing.T) {
}
conn.Close()
- if tries := 0; childRunning() {
- for tries < 15 && childRunning() {
- time.Sleep(50e6 * int64(tries))
- tries++
- }
- if childRunning() {
- t.Fatalf("post-conn.Close, expected child to be gone")
- }
+ tries := 0
+ for tries < 15 && childRunning() {
+ time.Sleep(50e6 * int64(tries))
+ tries++
+ }
+ if childRunning() {
+ t.Fatalf("post-conn.Close, expected child to be gone")
}
}
diff --git a/libgo/go/net/http/chunked.go b/libgo/go/net/http/chunked.go
index b012dd18496..74c41aabd41 100644
--- a/libgo/go/net/http/chunked.go
+++ b/libgo/go/net/http/chunked.go
@@ -2,20 +2,137 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// The wire protocol for HTTP's "chunked" Transfer-Encoding.
+
+// This code is duplicated in httputil/chunked.go.
+// Please make any changes in both files.
+
package http
import (
"bufio"
+ "bytes"
+ "errors"
"io"
"strconv"
)
+const maxLineLength = 4096 // assumed <= bufio.defaultBufSize
+
+var ErrLineTooLong = errors.New("header line too long")
+
+// newChunkedReader returns a new chunkedReader that translates the data read from r
+// out of HTTP "chunked" format before returning it.
+// The chunkedReader returns io.EOF when the final 0-length chunk is read.
+//
+// newChunkedReader is not needed by normal applications. The http package
+// automatically decodes chunking when reading response bodies.
+func newChunkedReader(r io.Reader) io.Reader {
+ br, ok := r.(*bufio.Reader)
+ if !ok {
+ br = bufio.NewReader(r)
+ }
+ return &chunkedReader{r: br}
+}
+
+type chunkedReader struct {
+ r *bufio.Reader
+ n uint64 // unread bytes in chunk
+ err error
+}
+
+func (cr *chunkedReader) beginChunk() {
+ // chunk-size CRLF
+ var line string
+ line, cr.err = readLine(cr.r)
+ if cr.err != nil {
+ return
+ }
+ cr.n, cr.err = strconv.Btoui64(line, 16)
+ if cr.err != nil {
+ return
+ }
+ if cr.n == 0 {
+ cr.err = io.EOF
+ }
+}
+
+func (cr *chunkedReader) Read(b []uint8) (n int, err error) {
+ if cr.err != nil {
+ return 0, cr.err
+ }
+ if cr.n == 0 {
+ cr.beginChunk()
+ if cr.err != nil {
+ return 0, cr.err
+ }
+ }
+ if uint64(len(b)) > cr.n {
+ b = b[0:cr.n]
+ }
+ n, cr.err = cr.r.Read(b)
+ cr.n -= uint64(n)
+ if cr.n == 0 && cr.err == nil {
+ // end of chunk (CRLF)
+ b := make([]byte, 2)
+ if _, cr.err = io.ReadFull(cr.r, b); cr.err == nil {
+ if b[0] != '\r' || b[1] != '\n' {
+ cr.err = errors.New("malformed chunked encoding")
+ }
+ }
+ }
+ return n, cr.err
+}
+
+// Read a line of bytes (up to \n) from b.
+// Give up if the line exceeds maxLineLength.
+// The returned bytes are a pointer into storage in
+// the bufio, so they are only valid until the next bufio read.
+func readLineBytes(b *bufio.Reader) (p []byte, err error) {
+ if p, err = b.ReadSlice('\n'); err != nil {
+ // We always know when EOF is coming.
+ // If the caller asked for a line, there should be a line.
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ } else if err == bufio.ErrBufferFull {
+ err = ErrLineTooLong
+ }
+ return nil, err
+ }
+ if len(p) >= maxLineLength {
+ return nil, ErrLineTooLong
+ }
+
+ // Chop off trailing white space.
+ p = bytes.TrimRight(p, " \r\t\n")
+
+ return p, nil
+}
+
+// readLineBytes, but convert the bytes into a string.
+func readLine(b *bufio.Reader) (s string, err error) {
+ p, e := readLineBytes(b)
+ if e != nil {
+ return "", e
+ }
+ return string(p), nil
+}
+
+// newChunkedWriter returns a new chunkedWriter that translates writes into HTTP
+// "chunked" format before writing them to w. Closing the returned chunkedWriter
+// sends the final 0-length chunk that marks the end of the stream.
+//
+// newChunkedWriter is not needed by normal applications. The http
+// package adds chunking automatically if handlers don't set a
+// Content-Length header. Using newChunkedWriter inside a handler
+// would result in double chunking or chunking with a Content-Length
+// length, both of which are wrong.
func newChunkedWriter(w io.Writer) io.WriteCloser {
return &chunkedWriter{w}
}
-// Writing to ChunkedWriter translates to writing in HTTP chunked Transfer
-// Encoding wire format to the underlying Wire writer.
+// Writing to chunkedWriter translates to writing in HTTP chunked Transfer
+// Encoding wire format to the underlying Wire chunkedWriter.
type chunkedWriter struct {
Wire io.Writer
}
@@ -51,7 +168,3 @@ func (cw *chunkedWriter) Close() error {
_, err := io.WriteString(cw.Wire, "0\r\n")
return err
}
-
-func newChunkedReader(r *bufio.Reader) io.Reader {
- return &chunkedReader{r: r}
-}
diff --git a/libgo/go/net/http/chunked_test.go b/libgo/go/net/http/chunked_test.go
new file mode 100644
index 00000000000..b77ee2ff26c
--- /dev/null
+++ b/libgo/go/net/http/chunked_test.go
@@ -0,0 +1,39 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This code is duplicated in httputil/chunked_test.go.
+// Please make any changes in both files.
+
+package http
+
+import (
+ "bytes"
+ "io/ioutil"
+ "testing"
+)
+
+func TestChunk(t *testing.T) {
+ var b bytes.Buffer
+
+ w := newChunkedWriter(&b)
+ const chunk1 = "hello, "
+ const chunk2 = "world! 0123456789abcdef"
+ w.Write([]byte(chunk1))
+ w.Write([]byte(chunk2))
+ w.Close()
+
+ if g, e := b.String(), "7\r\nhello, \r\n17\r\nworld! 0123456789abcdef\r\n0\r\n"; g != e {
+ t.Fatalf("chunk writer wrote %q; want %q", g, e)
+ }
+
+ r := newChunkedReader(&b)
+ data, err := ioutil.ReadAll(r)
+ if err != nil {
+ t.Logf(`data: "%s"`, data)
+ t.Fatalf("ReadAll from reader: %v", err)
+ }
+ if g, e := string(data), chunk1+chunk2; g != e {
+ t.Errorf("chunk reader read %q; want %q", g, e)
+ }
+}
diff --git a/libgo/go/net/http/client_test.go b/libgo/go/net/http/client_test.go
index d224380298c..57a9dd9574d 100644
--- a/libgo/go/net/http/client_test.go
+++ b/libgo/go/net/http/client_test.go
@@ -26,6 +26,31 @@ var robotsTxtHandler = HandlerFunc(func(w ResponseWriter, r *Request) {
fmt.Fprintf(w, "User-agent: go\nDisallow: /something/")
})
+// pedanticReadAll works like ioutil.ReadAll but additionally
+// verifies that r obeys the documented io.Reader contract.
+func pedanticReadAll(r io.Reader) (b []byte, err error) {
+ var bufa [64]byte
+ buf := bufa[:]
+ for {
+ n, err := r.Read(buf)
+ if n == 0 && err == nil {
+ return nil, fmt.Errorf("Read: n=0 with err=nil")
+ }
+ b = append(b, buf[:n]...)
+ if err == io.EOF {
+ n, err := r.Read(buf)
+ if n != 0 || err != io.EOF {
+ return nil, fmt.Errorf("Read: n=%d err=%#v after EOF", n, err)
+ }
+ return b, nil
+ }
+ if err != nil {
+ return b, err
+ }
+ }
+ panic("unreachable")
+}
+
func TestClient(t *testing.T) {
ts := httptest.NewServer(robotsTxtHandler)
defer ts.Close()
@@ -33,7 +58,7 @@ func TestClient(t *testing.T) {
r, err := Get(ts.URL)
var b []byte
if err == nil {
- b, err = ioutil.ReadAll(r.Body)
+ b, err = pedanticReadAll(r.Body)
r.Body.Close()
}
if err != nil {
diff --git a/libgo/go/net/http/fcgi/child.go b/libgo/go/net/http/fcgi/child.go
index 7b563951ccf..529440cbe92 100644
--- a/libgo/go/net/http/fcgi/child.go
+++ b/libgo/go/net/http/fcgi/child.go
@@ -7,6 +7,7 @@ package fcgi
// This file implements FastCGI from the perspective of a child process.
import (
+ "errors"
"fmt"
"io"
"net"
@@ -123,89 +124,101 @@ func (r *response) Close() error {
}
type child struct {
- conn *conn
- handler http.Handler
+ conn *conn
+ handler http.Handler
+ requests map[uint16]*request // keyed by request ID
}
-func newChild(rwc net.Conn, handler http.Handler) *child {
- return &child{newConn(rwc), handler}
+func newChild(rwc io.ReadWriteCloser, handler http.Handler) *child {
+ return &child{
+ conn: newConn(rwc),
+ handler: handler,
+ requests: make(map[uint16]*request),
+ }
}
func (c *child) serve() {
- requests := map[uint16]*request{}
defer c.conn.Close()
var rec record
- var br beginRequest
for {
if err := rec.read(c.conn.rwc); err != nil {
return
}
-
- req, ok := requests[rec.h.Id]
- if !ok && rec.h.Type != typeBeginRequest && rec.h.Type != typeGetValues {
- // The spec says to ignore unknown request IDs.
- continue
- }
- if ok && rec.h.Type == typeBeginRequest {
- // The server is trying to begin a request with the same ID
- // as an in-progress request. This is an error.
+ if err := c.handleRecord(&rec); err != nil {
return
}
+ }
+}
- switch rec.h.Type {
- case typeBeginRequest:
- if err := br.read(rec.content()); err != nil {
- return
- }
- if br.role != roleResponder {
- c.conn.writeEndRequest(rec.h.Id, 0, statusUnknownRole)
- break
- }
- requests[rec.h.Id] = newRequest(rec.h.Id, br.flags)
- case typeParams:
- // NOTE(eds): Technically a key-value pair can straddle the boundary
- // between two packets. We buffer until we've received all parameters.
- if len(rec.content()) > 0 {
- req.rawParams = append(req.rawParams, rec.content()...)
- break
- }
- req.parseParams()
- case typeStdin:
- content := rec.content()
- if req.pw == nil {
- var body io.ReadCloser
- if len(content) > 0 {
- // body could be an io.LimitReader, but it shouldn't matter
- // as long as both sides are behaving.
- body, req.pw = io.Pipe()
- }
- go c.serveRequest(req, body)
- }
+var errCloseConn = errors.New("fcgi: connection should be closed")
+
+func (c *child) handleRecord(rec *record) error {
+ req, ok := c.requests[rec.h.Id]
+ if !ok && rec.h.Type != typeBeginRequest && rec.h.Type != typeGetValues {
+ // The spec says to ignore unknown request IDs.
+ return nil
+ }
+ if ok && rec.h.Type == typeBeginRequest {
+ // The server is trying to begin a request with the same ID
+ // as an in-progress request. This is an error.
+ return errors.New("fcgi: received ID that is already in-flight")
+ }
+
+ switch rec.h.Type {
+ case typeBeginRequest:
+ var br beginRequest
+ if err := br.read(rec.content()); err != nil {
+ return err
+ }
+ if br.role != roleResponder {
+ c.conn.writeEndRequest(rec.h.Id, 0, statusUnknownRole)
+ return nil
+ }
+ c.requests[rec.h.Id] = newRequest(rec.h.Id, br.flags)
+ case typeParams:
+ // NOTE(eds): Technically a key-value pair can straddle the boundary
+ // between two packets. We buffer until we've received all parameters.
+ if len(rec.content()) > 0 {
+ req.rawParams = append(req.rawParams, rec.content()...)
+ return nil
+ }
+ req.parseParams()
+ case typeStdin:
+ content := rec.content()
+ if req.pw == nil {
+ var body io.ReadCloser
if len(content) > 0 {
- // TODO(eds): This blocks until the handler reads from the pipe.
- // If the handler takes a long time, it might be a problem.
- req.pw.Write(content)
- } else if req.pw != nil {
- req.pw.Close()
- }
- case typeGetValues:
- values := map[string]string{"FCGI_MPXS_CONNS": "1"}
- c.conn.writePairs(0, typeGetValuesResult, values)
- case typeData:
- // If the filter role is implemented, read the data stream here.
- case typeAbortRequest:
- delete(requests, rec.h.Id)
- c.conn.writeEndRequest(rec.h.Id, 0, statusRequestComplete)
- if !req.keepConn {
- // connection will close upon return
- return
+ // body could be an io.LimitReader, but it shouldn't matter
+ // as long as both sides are behaving.
+ body, req.pw = io.Pipe()
}
- default:
- b := make([]byte, 8)
- b[0] = rec.h.Type
- c.conn.writeRecord(typeUnknownType, 0, b)
+ go c.serveRequest(req, body)
+ }
+ if len(content) > 0 {
+ // TODO(eds): This blocks until the handler reads from the pipe.
+ // If the handler takes a long time, it might be a problem.
+ req.pw.Write(content)
+ } else if req.pw != nil {
+ req.pw.Close()
+ }
+ case typeGetValues:
+ values := map[string]string{"FCGI_MPXS_CONNS": "1"}
+ c.conn.writePairs(typeGetValuesResult, 0, values)
+ case typeData:
+ // If the filter role is implemented, read the data stream here.
+ case typeAbortRequest:
+ delete(c.requests, rec.h.Id)
+ c.conn.writeEndRequest(rec.h.Id, 0, statusRequestComplete)
+ if !req.keepConn {
+ // connection will close upon return
+ return errCloseConn
}
+ default:
+ b := make([]byte, 8)
+ b[0] = byte(rec.h.Type)
+ c.conn.writeRecord(typeUnknownType, 0, b)
}
+ return nil
}
func (c *child) serveRequest(req *request, body io.ReadCloser) {
diff --git a/libgo/go/net/http/fcgi/fcgi.go b/libgo/go/net/http/fcgi/fcgi.go
index 70cf781e228..d35aa84d229 100644
--- a/libgo/go/net/http/fcgi/fcgi.go
+++ b/libgo/go/net/http/fcgi/fcgi.go
@@ -19,19 +19,22 @@ import (
"sync"
)
+// recType is a record type, as defined by
+// http://www.fastcgi.com/devkit/doc/fcgi-spec.html#S8
+type recType uint8
+
const (
- // Packet Types
- typeBeginRequest = iota + 1
- typeAbortRequest
- typeEndRequest
- typeParams
- typeStdin
- typeStdout
- typeStderr
- typeData
- typeGetValues
- typeGetValuesResult
- typeUnknownType
+ typeBeginRequest recType = 1
+ typeAbortRequest recType = 2
+ typeEndRequest recType = 3
+ typeParams recType = 4
+ typeStdin recType = 5
+ typeStdout recType = 6
+ typeStderr recType = 7
+ typeData recType = 8
+ typeGetValues recType = 9
+ typeGetValuesResult recType = 10
+ typeUnknownType recType = 11
)
// keep the connection between web-server and responder open after request
@@ -59,7 +62,7 @@ const headerLen = 8
type header struct {
Version uint8
- Type uint8
+ Type recType
Id uint16
ContentLength uint16
PaddingLength uint8
@@ -85,7 +88,7 @@ func (br *beginRequest) read(content []byte) error {
// not synchronized because we don't care what the contents are
var pad [maxPad]byte
-func (h *header) init(recType uint8, reqId uint16, contentLength int) {
+func (h *header) init(recType recType, reqId uint16, contentLength int) {
h.Version = 1
h.Type = recType
h.Id = reqId
@@ -137,7 +140,7 @@ func (r *record) content() []byte {
}
// writeRecord writes and sends a single record.
-func (c *conn) writeRecord(recType uint8, reqId uint16, b []byte) error {
+func (c *conn) writeRecord(recType recType, reqId uint16, b []byte) error {
c.mutex.Lock()
defer c.mutex.Unlock()
c.buf.Reset()
@@ -167,12 +170,12 @@ func (c *conn) writeEndRequest(reqId uint16, appStatus int, protocolStatus uint8
return c.writeRecord(typeEndRequest, reqId, b)
}
-func (c *conn) writePairs(recType uint8, reqId uint16, pairs map[string]string) error {
+func (c *conn) writePairs(recType recType, reqId uint16, pairs map[string]string) error {
w := newWriter(c, recType, reqId)
b := make([]byte, 8)
for k, v := range pairs {
n := encodeSize(b, uint32(len(k)))
- n += encodeSize(b[n:], uint32(len(k)))
+ n += encodeSize(b[n:], uint32(len(v)))
if _, err := w.Write(b[:n]); err != nil {
return err
}
@@ -235,7 +238,7 @@ func (w *bufWriter) Close() error {
return w.closer.Close()
}
-func newWriter(c *conn, recType uint8, reqId uint16) *bufWriter {
+func newWriter(c *conn, recType recType, reqId uint16) *bufWriter {
s := &streamWriter{c: c, recType: recType, reqId: reqId}
w, _ := bufio.NewWriterSize(s, maxWrite)
return &bufWriter{s, w}
@@ -245,7 +248,7 @@ func newWriter(c *conn, recType uint8, reqId uint16) *bufWriter {
// It only writes maxWrite bytes at a time.
type streamWriter struct {
c *conn
- recType uint8
+ recType recType
reqId uint16
}
diff --git a/libgo/go/net/http/fcgi/fcgi_test.go b/libgo/go/net/http/fcgi/fcgi_test.go
index e42f8efd658..6c7e1a9ce83 100644
--- a/libgo/go/net/http/fcgi/fcgi_test.go
+++ b/libgo/go/net/http/fcgi/fcgi_test.go
@@ -6,6 +6,7 @@ package fcgi
import (
"bytes"
+ "errors"
"io"
"testing"
)
@@ -40,25 +41,25 @@ func TestSize(t *testing.T) {
var streamTests = []struct {
desc string
- recType uint8
+ recType recType
reqId uint16
content []byte
raw []byte
}{
{"single record", typeStdout, 1, nil,
- []byte{1, typeStdout, 0, 1, 0, 0, 0, 0},
+ []byte{1, byte(typeStdout), 0, 1, 0, 0, 0, 0},
},
// this data will have to be split into two records
{"two records", typeStdin, 300, make([]byte, 66000),
bytes.Join([][]byte{
// header for the first record
- {1, typeStdin, 0x01, 0x2C, 0xFF, 0xFF, 1, 0},
+ {1, byte(typeStdin), 0x01, 0x2C, 0xFF, 0xFF, 1, 0},
make([]byte, 65536),
// header for the second
- {1, typeStdin, 0x01, 0x2C, 0x01, 0xD1, 7, 0},
+ {1, byte(typeStdin), 0x01, 0x2C, 0x01, 0xD1, 7, 0},
make([]byte, 472),
// header for the empty record
- {1, typeStdin, 0x01, 0x2C, 0, 0, 0, 0},
+ {1, byte(typeStdin), 0x01, 0x2C, 0, 0, 0, 0},
},
nil),
},
@@ -111,3 +112,39 @@ outer:
}
}
}
+
+type writeOnlyConn struct {
+ buf []byte
+}
+
+func (c *writeOnlyConn) Write(p []byte) (int, error) {
+ c.buf = append(c.buf, p...)
+ return len(p), nil
+}
+
+func (c *writeOnlyConn) Read(p []byte) (int, error) {
+ return 0, errors.New("conn is write-only")
+}
+
+func (c *writeOnlyConn) Close() error {
+ return nil
+}
+
+func TestGetValues(t *testing.T) {
+ var rec record
+ rec.h.Type = typeGetValues
+
+ wc := new(writeOnlyConn)
+ c := newChild(wc, nil)
+ err := c.handleRecord(&rec)
+ if err != nil {
+ t.Fatalf("handleRecord: %v", err)
+ }
+
+ const want = "\x01\n\x00\x00\x00\x12\x06\x00" +
+ "\x0f\x01FCGI_MPXS_CONNS1" +
+ "\x00\x00\x00\x00\x00\x00\x01\n\x00\x00\x00\x00\x00\x00"
+ if got := string(wc.buf); got != want {
+ t.Errorf(" got: %q\nwant: %q\n", got, want)
+ }
+}
diff --git a/libgo/go/net/http/fs.go b/libgo/go/net/http/fs.go
index 5f91ff5cbf6..5aadac17a23 100644
--- a/libgo/go/net/http/fs.go
+++ b/libgo/go/net/http/fs.go
@@ -22,13 +22,19 @@ import (
// A Dir implements http.FileSystem using the native file
// system restricted to a specific directory tree.
+//
+// An empty Dir is treated as ".".
type Dir string
func (d Dir) Open(name string) (File, error) {
if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 {
return nil, errors.New("http: invalid character in file path")
}
- f, err := os.Open(filepath.Join(string(d), filepath.FromSlash(path.Clean("/"+name))))
+ dir := string(d)
+ if dir == "" {
+ dir = "."
+ }
+ f, err := os.Open(filepath.Join(dir, filepath.FromSlash(path.Clean("/"+name))))
if err != nil {
return nil, err
}
diff --git a/libgo/go/net/http/fs_test.go b/libgo/go/net/http/fs_test.go
index e1a784c1f6d..6697189900e 100644
--- a/libgo/go/net/http/fs_test.go
+++ b/libgo/go/net/http/fs_test.go
@@ -208,6 +208,20 @@ func TestDirJoin(t *testing.T) {
test(Dir("/etc/hosts"), "../")
}
+func TestEmptyDirOpenCWD(t *testing.T) {
+ test := func(d Dir) {
+ name := "fs_test.go"
+ f, err := d.Open(name)
+ if err != nil {
+ t.Fatalf("open of %s: %v", name, err)
+ }
+ defer f.Close()
+ }
+ test(Dir(""))
+ test(Dir("."))
+ test(Dir("./"))
+}
+
func TestServeFileContentType(t *testing.T) {
const ctype = "icecream/chocolate"
override := false
@@ -247,6 +261,20 @@ func TestServeFileMimeType(t *testing.T) {
}
}
+func TestServeFileFromCWD(t *testing.T) {
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ ServeFile(w, r, "fs_test.go")
+ }))
+ defer ts.Close()
+ r, err := Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if r.StatusCode != 200 {
+ t.Fatalf("expected 200 OK, got %s", r.Status)
+ }
+}
+
func TestServeFileWithContentEncoding(t *testing.T) {
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
w.Header().Set("Content-Encoding", "foo")
diff --git a/libgo/go/net/http/httputil/chunked.go b/libgo/go/net/http/httputil/chunked.go
index 34e47c796c1..69bcc0e816f 100644
--- a/libgo/go/net/http/httputil/chunked.go
+++ b/libgo/go/net/http/httputil/chunked.go
@@ -2,18 +2,126 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// The wire protocol for HTTP's "chunked" Transfer-Encoding.
+
+// This code is a duplicate of ../chunked.go with these edits:
+// s/newChunked/NewChunked/g
+// s/package http/package httputil/
+// Please make any changes in both files.
+
package httputil
import (
"bufio"
+ "bytes"
+ "errors"
"io"
- "net/http"
"strconv"
- "strings"
)
-// NewChunkedWriter returns a new writer that translates writes into HTTP
-// "chunked" format before writing them to w. Closing the returned writer
+const maxLineLength = 4096 // assumed <= bufio.defaultBufSize
+
+var ErrLineTooLong = errors.New("header line too long")
+
+// NewChunkedReader returns a new chunkedReader that translates the data read from r
+// out of HTTP "chunked" format before returning it.
+// The chunkedReader returns io.EOF when the final 0-length chunk is read.
+//
+// NewChunkedReader is not needed by normal applications. The http package
+// automatically decodes chunking when reading response bodies.
+func NewChunkedReader(r io.Reader) io.Reader {
+ br, ok := r.(*bufio.Reader)
+ if !ok {
+ br = bufio.NewReader(r)
+ }
+ return &chunkedReader{r: br}
+}
+
+type chunkedReader struct {
+ r *bufio.Reader
+ n uint64 // unread bytes in chunk
+ err error
+}
+
+func (cr *chunkedReader) beginChunk() {
+ // chunk-size CRLF
+ var line string
+ line, cr.err = readLine(cr.r)
+ if cr.err != nil {
+ return
+ }
+ cr.n, cr.err = strconv.Btoui64(line, 16)
+ if cr.err != nil {
+ return
+ }
+ if cr.n == 0 {
+ cr.err = io.EOF
+ }
+}
+
+func (cr *chunkedReader) Read(b []uint8) (n int, err error) {
+ if cr.err != nil {
+ return 0, cr.err
+ }
+ if cr.n == 0 {
+ cr.beginChunk()
+ if cr.err != nil {
+ return 0, cr.err
+ }
+ }
+ if uint64(len(b)) > cr.n {
+ b = b[0:cr.n]
+ }
+ n, cr.err = cr.r.Read(b)
+ cr.n -= uint64(n)
+ if cr.n == 0 && cr.err == nil {
+ // end of chunk (CRLF)
+ b := make([]byte, 2)
+ if _, cr.err = io.ReadFull(cr.r, b); cr.err == nil {
+ if b[0] != '\r' || b[1] != '\n' {
+ cr.err = errors.New("malformed chunked encoding")
+ }
+ }
+ }
+ return n, cr.err
+}
+
+// Read a line of bytes (up to \n) from b.
+// Give up if the line exceeds maxLineLength.
+// The returned bytes are a pointer into storage in
+// the bufio, so they are only valid until the next bufio read.
+func readLineBytes(b *bufio.Reader) (p []byte, err error) {
+ if p, err = b.ReadSlice('\n'); err != nil {
+ // We always know when EOF is coming.
+ // If the caller asked for a line, there should be a line.
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ } else if err == bufio.ErrBufferFull {
+ err = ErrLineTooLong
+ }
+ return nil, err
+ }
+ if len(p) >= maxLineLength {
+ return nil, ErrLineTooLong
+ }
+
+ // Chop off trailing white space.
+ p = bytes.TrimRight(p, " \r\t\n")
+
+ return p, nil
+}
+
+// readLineBytes, but convert the bytes into a string.
+func readLine(b *bufio.Reader) (s string, err error) {
+ p, e := readLineBytes(b)
+ if e != nil {
+ return "", e
+ }
+ return string(p), nil
+}
+
+// NewChunkedWriter returns a new chunkedWriter that translates writes into HTTP
+// "chunked" format before writing them to w. Closing the returned chunkedWriter
// sends the final 0-length chunk that marks the end of the stream.
//
// NewChunkedWriter is not needed by normal applications. The http
@@ -25,8 +133,8 @@ func NewChunkedWriter(w io.Writer) io.WriteCloser {
return &chunkedWriter{w}
}
-// Writing to ChunkedWriter translates to writing in HTTP chunked Transfer
-// Encoding wire format to the underlying Wire writer.
+// Writing to chunkedWriter translates to writing in HTTP chunked Transfer
+// Encoding wire format to the underlying Wire chunkedWriter.
type chunkedWriter struct {
Wire io.Writer
}
@@ -62,23 +170,3 @@ func (cw *chunkedWriter) Close() error {
_, err := io.WriteString(cw.Wire, "0\r\n")
return err
}
-
-// NewChunkedReader returns a new reader that translates the data read from r
-// out of HTTP "chunked" format before returning it.
-// The reader returns io.EOF when the final 0-length chunk is read.
-//
-// NewChunkedReader is not needed by normal applications. The http package
-// automatically decodes chunking when reading response bodies.
-func NewChunkedReader(r io.Reader) io.Reader {
- // This is a bit of a hack so we don't have to copy chunkedReader into
- // httputil. It's a bit more complex than chunkedWriter, which is copied
- // above.
- req, err := http.ReadRequest(bufio.NewReader(io.MultiReader(
- strings.NewReader("POST / HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n"),
- r,
- strings.NewReader("\r\n"))))
- if err != nil {
- panic("bad fake request: " + err.Error())
- }
- return req.Body
-}
diff --git a/libgo/go/net/http/httputil/chunked_test.go b/libgo/go/net/http/httputil/chunked_test.go
index 258d39b93cb..155a32bdf9a 100644
--- a/libgo/go/net/http/httputil/chunked_test.go
+++ b/libgo/go/net/http/httputil/chunked_test.go
@@ -2,6 +2,11 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// This code is a duplicate of ../chunked_test.go with these edits:
+// s/newChunked/NewChunked/g
+// s/package http/package httputil/
+// Please make any changes in both files.
+
package httputil
import (
@@ -27,7 +32,8 @@ func TestChunk(t *testing.T) {
r := NewChunkedReader(&b)
data, err := ioutil.ReadAll(r)
if err != nil {
- t.Fatalf("ReadAll from NewChunkedReader: %v", err)
+ t.Logf(`data: "%s"`, data)
+ t.Fatalf("ReadAll from reader: %v", err)
}
if g, e := string(data), chunk1+chunk2; g != e {
t.Errorf("chunk reader read %q; want %q", g, e)
diff --git a/libgo/go/net/http/httputil/persist.go b/libgo/go/net/http/httputil/persist.go
index d7b670110c4..1266bd3ad22 100644
--- a/libgo/go/net/http/httputil/persist.go
+++ b/libgo/go/net/http/httputil/persist.go
@@ -22,6 +22,10 @@ var (
ErrPipeline = &http.ProtocolError{"pipeline error"}
)
+// This is an API usage error - the local side is closed.
+// ErrPersistEOF (above) reports that the remote side is closed.
+var errClosed = errors.New("i/o operation on closed connection")
+
// A ServerConn reads requests and sends responses over an underlying
// connection, until the HTTP keepalive logic commands an end. ServerConn
// also allows hijacking the underlying connection by calling Hijack
@@ -108,7 +112,7 @@ func (sc *ServerConn) Read() (req *http.Request, err error) {
}
if sc.r == nil { // connection closed by user in the meantime
defer sc.lk.Unlock()
- return nil, os.EBADF
+ return nil, errClosed
}
r := sc.r
lastbody := sc.lastbody
@@ -313,7 +317,7 @@ func (cc *ClientConn) Write(req *http.Request) (err error) {
}
if cc.c == nil { // connection closed by user in the meantime
defer cc.lk.Unlock()
- return os.EBADF
+ return errClosed
}
c := cc.c
if req.Close {
@@ -369,7 +373,7 @@ func (cc *ClientConn) Read(req *http.Request) (resp *http.Response, err error) {
}
if cc.r == nil { // connection closed by user in the meantime
defer cc.lk.Unlock()
- return nil, os.EBADF
+ return nil, errClosed
}
r := cc.r
lastbody := cc.lastbody
diff --git a/libgo/go/net/http/readrequest_test.go b/libgo/go/net/http/readrequest_test.go
index 2219d433165..c64fff6109f 100644
--- a/libgo/go/net/http/readrequest_test.go
+++ b/libgo/go/net/http/readrequest_test.go
@@ -70,7 +70,6 @@ var reqTests = []reqTest{
Close: false,
ContentLength: 7,
Host: "www.techcrunch.com",
- Form: url.Values{},
},
"abcdef\n",
@@ -94,10 +93,10 @@ var reqTests = []reqTest{
Proto: "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,
+ Header: Header{},
Close: false,
ContentLength: 0,
Host: "foo.com",
- Form: url.Values{},
},
noBody,
@@ -131,7 +130,6 @@ var reqTests = []reqTest{
Close: false,
ContentLength: 0,
Host: "test",
- Form: url.Values{},
},
noBody,
@@ -180,9 +178,9 @@ var reqTests = []reqTest{
Proto: "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,
+ Header: Header{},
ContentLength: -1,
Host: "foo.com",
- Form: url.Values{},
},
"foobar",
diff --git a/libgo/go/net/http/request.go b/libgo/go/net/http/request.go
index 4410ca1d11c..66178490e37 100644
--- a/libgo/go/net/http/request.go
+++ b/libgo/go/net/http/request.go
@@ -19,12 +19,10 @@ import (
"mime/multipart"
"net/textproto"
"net/url"
- "strconv"
"strings"
)
const (
- maxLineLength = 4096 // assumed <= bufio.defaultBufSize
maxValueLength = 4096
maxHeaderLines = 1024
chunkSize = 4 << 10 // 4 KB chunks
@@ -43,7 +41,6 @@ type ProtocolError struct {
func (err *ProtocolError) Error() string { return err.ErrorString }
var (
- ErrLineTooLong = &ProtocolError{"header line too long"}
ErrHeaderTooLong = &ProtocolError{"header too long"}
ErrShortBody = &ProtocolError{"entity body too short"}
ErrNotSupported = &ProtocolError{"feature not supported"}
@@ -375,44 +372,6 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header) err
return nil
}
-// Read a line of bytes (up to \n) from b.
-// Give up if the line exceeds maxLineLength.
-// The returned bytes are a pointer into storage in
-// the bufio, so they are only valid until the next bufio read.
-func readLineBytes(b *bufio.Reader) (p []byte, err error) {
- if p, err = b.ReadSlice('\n'); err != nil {
- // We always know when EOF is coming.
- // If the caller asked for a line, there should be a line.
- if err == io.EOF {
- err = io.ErrUnexpectedEOF
- } else if err == bufio.ErrBufferFull {
- err = ErrLineTooLong
- }
- return nil, err
- }
- if len(p) >= maxLineLength {
- return nil, ErrLineTooLong
- }
-
- // Chop off trailing white space.
- var i int
- for i = len(p); i > 0; i-- {
- if c := p[i-1]; c != ' ' && c != '\r' && c != '\t' && c != '\n' {
- break
- }
- }
- return p[0:i], nil
-}
-
-// readLineBytes, but convert the bytes into a string.
-func readLine(b *bufio.Reader) (s string, err error) {
- p, e := readLineBytes(b)
- if e != nil {
- return "", e
- }
- return string(p), nil
-}
-
// Convert decimal at s[i:len(s)] to integer,
// returning value, string position where the digits stopped,
// and whether there was a valid number (digits, not too big).
@@ -448,55 +407,6 @@ func ParseHTTPVersion(vers string) (major, minor int, ok bool) {
return major, minor, true
}
-type chunkedReader struct {
- r *bufio.Reader
- n uint64 // unread bytes in chunk
- err error
-}
-
-func (cr *chunkedReader) beginChunk() {
- // chunk-size CRLF
- var line string
- line, cr.err = readLine(cr.r)
- if cr.err != nil {
- return
- }
- cr.n, cr.err = strconv.Btoui64(line, 16)
- if cr.err != nil {
- return
- }
- if cr.n == 0 {
- cr.err = io.EOF
- }
-}
-
-func (cr *chunkedReader) Read(b []uint8) (n int, err error) {
- if cr.err != nil {
- return 0, cr.err
- }
- if cr.n == 0 {
- cr.beginChunk()
- if cr.err != nil {
- return 0, cr.err
- }
- }
- if uint64(len(b)) > cr.n {
- b = b[0:cr.n]
- }
- n, cr.err = cr.r.Read(b)
- cr.n -= uint64(n)
- if cr.n == 0 && cr.err == nil {
- // end of chunk (CRLF)
- b := make([]byte, 2)
- if _, cr.err = io.ReadFull(cr.r, b); cr.err == nil {
- if b[0] != '\r' || b[1] != '\n' {
- cr.err = errors.New("malformed chunked encoding")
- }
- }
- }
- return n, cr.err
-}
-
// NewRequest returns a new Request given a method, URL, and optional body.
func NewRequest(method, urlStr string, body io.Reader) (*Request, error) {
u, err := url.Parse(urlStr)
diff --git a/libgo/go/net/http/response_test.go b/libgo/go/net/http/response_test.go
index be717aa83c3..e5d01698e55 100644
--- a/libgo/go/net/http/response_test.go
+++ b/libgo/go/net/http/response_test.go
@@ -65,6 +65,7 @@ var respTests = []respTest{
Proto: "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,
+ Header: Header{},
Request: dummyReq("GET"),
Close: true,
ContentLength: -1,
@@ -85,6 +86,7 @@ var respTests = []respTest{
Proto: "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,
+ Header: Header{},
Request: dummyReq("GET"),
Close: false,
ContentLength: 0,
@@ -315,7 +317,7 @@ func TestReadResponseCloseInMiddle(t *testing.T) {
}
var wr io.Writer = &buf
if test.chunked {
- wr = &chunkedWriter{wr}
+ wr = newChunkedWriter(wr)
}
if test.compressed {
buf.WriteString("Content-Encoding: gzip\r\n")
diff --git a/libgo/go/net/http/serve_test.go b/libgo/go/net/http/serve_test.go
index e278396091d..97a0b139e39 100644
--- a/libgo/go/net/http/serve_test.go
+++ b/libgo/go/net/http/serve_test.go
@@ -1077,6 +1077,31 @@ func TestClientWriteShutdown(t *testing.T) {
}
}
+// Tests that chunked server responses that write 1 byte at a time are
+// buffered before chunk headers are added, not after chunk headers.
+func TestServerBufferedChunking(t *testing.T) {
+ if true {
+ t.Logf("Skipping known broken test; see Issue 2357")
+ return
+ }
+ conn := new(testConn)
+ conn.readBuf.Write([]byte("GET / HTTP/1.1\r\n\r\n"))
+ done := make(chan bool)
+ ls := &oneConnListener{conn}
+ go Serve(ls, HandlerFunc(func(rw ResponseWriter, req *Request) {
+ defer close(done)
+ rw.Header().Set("Content-Type", "text/plain") // prevent sniffing, which buffers
+ rw.Write([]byte{'x'})
+ rw.Write([]byte{'y'})
+ rw.Write([]byte{'z'})
+ }))
+ <-done
+ if !bytes.HasSuffix(conn.writeBuf.Bytes(), []byte("\r\n\r\n3\r\nxyz\r\n0\r\n\r\n")) {
+ t.Errorf("response didn't end with a single 3 byte 'xyz' chunk; got:\n%q",
+ conn.writeBuf.Bytes())
+ }
+}
+
// goTimeout runs f, failing t if f takes more than ns to complete.
func goTimeout(t *testing.T, ns int64, f func()) {
ch := make(chan bool, 2)
@@ -1120,7 +1145,7 @@ func TestAcceptMaxFds(t *testing.T) {
ln := &errorListener{[]error{
&net.OpError{
Op: "accept",
- Err: os.Errno(syscall.EMFILE),
+ Err: syscall.EMFILE,
}}}
err := Serve(ln, HandlerFunc(HandlerFunc(func(ResponseWriter, *Request) {})))
if err != io.EOF {
diff --git a/libgo/go/net/http/server.go b/libgo/go/net/http/server.go
index 8c4889436f1..7221d2508bb 100644
--- a/libgo/go/net/http/server.go
+++ b/libgo/go/net/http/server.go
@@ -149,11 +149,13 @@ type writerOnly struct {
}
func (w *response) ReadFrom(src io.Reader) (n int64, err error) {
- // Flush before checking w.chunking, as Flush will call
- // WriteHeader if it hasn't been called yet, and WriteHeader
- // is what sets w.chunking.
- w.Flush()
+ // Call WriteHeader before checking w.chunking if it hasn't
+ // been called yet, since WriteHeader is what sets w.chunking.
+ if !w.wroteHeader {
+ w.WriteHeader(StatusOK)
+ }
if !w.chunking && w.bodyAllowed() && !w.needSniff {
+ w.Flush()
if rf, ok := w.conn.rwc.(io.ReaderFrom); ok {
n, err = rf.ReadFrom(src)
w.written += n
diff --git a/libgo/go/net/http/sniff_test.go b/libgo/go/net/http/sniff_test.go
index a414e6420db..86744eeb56b 100644
--- a/libgo/go/net/http/sniff_test.go
+++ b/libgo/go/net/http/sniff_test.go
@@ -6,6 +6,7 @@ package http_test
import (
"bytes"
+ "io"
"io/ioutil"
"log"
. "net/http"
@@ -79,3 +80,35 @@ func TestServerContentType(t *testing.T) {
resp.Body.Close()
}
}
+
+func TestContentTypeWithCopy(t *testing.T) {
+ const (
+ input = "\n<html>\n\t<head>\n"
+ expected = "text/html; charset=utf-8"
+ )
+
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ // Use io.Copy from a bytes.Buffer to trigger ReadFrom.
+ buf := bytes.NewBuffer([]byte(input))
+ n, err := io.Copy(w, buf)
+ if int(n) != len(input) || err != nil {
+ t.Errorf("io.Copy(w, %q) = %v, %v want %d, nil", input, n, err, len(input))
+ }
+ }))
+ defer ts.Close()
+
+ resp, err := Get(ts.URL)
+ if err != nil {
+ t.Fatalf("Get: %v", err)
+ }
+ if ct := resp.Header.Get("Content-Type"); ct != expected {
+ t.Errorf("Content-Type = %q, want %q", ct, expected)
+ }
+ data, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ t.Errorf("reading body: %v", err)
+ } else if !bytes.Equal(data, []byte(input)) {
+ t.Errorf("data is %q, want %q", data, input)
+ }
+ resp.Body.Close()
+}
diff --git a/libgo/go/net/http/transfer.go b/libgo/go/net/http/transfer.go
index 2670d77ef00..d25c8fcde42 100644
--- a/libgo/go/net/http/transfer.go
+++ b/libgo/go/net/http/transfer.go
@@ -537,7 +537,9 @@ func (b *body) Read(p []byte) (n int, err error) {
// Read the final trailer once we hit EOF.
if err == io.EOF && b.hdr != nil {
- err = b.readTrailer()
+ if e := b.readTrailer(); e != nil {
+ err = e
+ }
b.hdr = nil
}
return n, err
diff --git a/libgo/go/net/http/transport.go b/libgo/go/net/http/transport.go
index da5244b2c12..e622e41f0a2 100644
--- a/libgo/go/net/http/transport.go
+++ b/libgo/go/net/http/transport.go
@@ -504,7 +504,7 @@ func (pc *persistConn) expectingResponse() bool {
var remoteSideClosedFunc func(error) bool // or nil to use default
func remoteSideClosed(err error) bool {
- if err == io.EOF || err == os.EINVAL {
+ if err == io.EOF {
return true
}
if remoteSideClosedFunc != nil {
diff --git a/libgo/go/net/http/transport_windows.go b/libgo/go/net/http/transport_windows.go
index 2a20d2224ae..c9ef2c2ab6e 100644
--- a/libgo/go/net/http/transport_windows.go
+++ b/libgo/go/net/http/transport_windows.go
@@ -6,14 +6,14 @@ package http
import (
"net"
- "os"
+ "syscall"
)
func init() {
remoteSideClosedFunc = func(err error) (out bool) {
op, ok := err.(*net.OpError)
- if ok && op.Op == "WSARecv" && op.Net == "tcp" && op.Err == os.Errno(10058) {
- // TODO(bradfitz): find the symbol for 10058
+ if ok && op.Op == "WSARecv" && op.Net == "tcp" && op.Err == syscall.Errno(10058) {
+ // TODO(brainman,rsc): Fix whatever is generating this.
return true
}
return false
diff --git a/libgo/go/net/interface_bsd.go b/libgo/go/net/interface_bsd.go
index b026e01104d..e896d43c321 100644
--- a/libgo/go/net/interface_bsd.go
+++ b/libgo/go/net/interface_bsd.go
@@ -20,18 +20,18 @@ import (
func interfaceTable(ifindex int) ([]Interface, error) {
var (
tab []byte
- e int
+ e error
msgs []syscall.RoutingMessage
ift []Interface
)
tab, e = syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex)
- if e != 0 {
+ if e != nil {
return nil, os.NewSyscallError("route rib", e)
}
msgs, e = syscall.ParseRoutingMessage(tab)
- if e != 0 {
+ if e != nil {
return nil, os.NewSyscallError("route message", e)
}
@@ -55,7 +55,7 @@ func newLink(m *syscall.InterfaceMessage) ([]Interface, error) {
var ift []Interface
sas, e := syscall.ParseRoutingSockaddr(m)
- if e != 0 {
+ if e != nil {
return nil, os.NewSyscallError("route sockaddr", e)
}
@@ -110,18 +110,18 @@ func linkFlags(rawFlags int32) Flags {
func interfaceAddrTable(ifindex int) ([]Addr, error) {
var (
tab []byte
- e int
+ e error
msgs []syscall.RoutingMessage
ifat []Addr
)
tab, e = syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex)
- if e != 0 {
+ if e != nil {
return nil, os.NewSyscallError("route rib", e)
}
msgs, e = syscall.ParseRoutingMessage(tab)
- if e != 0 {
+ if e != nil {
return nil, os.NewSyscallError("route message", e)
}
@@ -145,7 +145,7 @@ func newAddr(m *syscall.InterfaceAddrMessage) ([]Addr, error) {
var ifat []Addr
sas, e := syscall.ParseRoutingSockaddr(m)
- if e != 0 {
+ if e != nil {
return nil, os.NewSyscallError("route sockaddr", e)
}
diff --git a/libgo/go/net/interface_darwin.go b/libgo/go/net/interface_darwin.go
index 1472afb8846..2da447adc84 100644
--- a/libgo/go/net/interface_darwin.go
+++ b/libgo/go/net/interface_darwin.go
@@ -17,18 +17,18 @@ import (
func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
var (
tab []byte
- e int
+ e error
msgs []syscall.RoutingMessage
ifmat []Addr
)
tab, e = syscall.RouteRIB(syscall.NET_RT_IFLIST2, ifindex)
- if e != 0 {
+ if e != nil {
return nil, os.NewSyscallError("route rib", e)
}
msgs, e = syscall.ParseRoutingMessage(tab)
- if e != 0 {
+ if e != nil {
return nil, os.NewSyscallError("route message", e)
}
@@ -52,7 +52,7 @@ func newMulticastAddr(m *syscall.InterfaceMulticastAddrMessage) ([]Addr, error)
var ifmat []Addr
sas, e := syscall.ParseRoutingSockaddr(m)
- if e != 0 {
+ if e != nil {
return nil, os.NewSyscallError("route sockaddr", e)
}
diff --git a/libgo/go/net/interface_freebsd.go b/libgo/go/net/interface_freebsd.go
index b0274f68d75..a12877e251b 100644
--- a/libgo/go/net/interface_freebsd.go
+++ b/libgo/go/net/interface_freebsd.go
@@ -17,18 +17,18 @@ import (
func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
var (
tab []byte
- e int
+ e error
msgs []syscall.RoutingMessage
ifmat []Addr
)
tab, e = syscall.RouteRIB(syscall.NET_RT_IFMALIST, ifindex)
- if e != 0 {
+ if e != nil {
return nil, os.NewSyscallError("route rib", e)
}
msgs, e = syscall.ParseRoutingMessage(tab)
- if e != 0 {
+ if e != nil {
return nil, os.NewSyscallError("route message", e)
}
@@ -52,7 +52,7 @@ func newMulticastAddr(m *syscall.InterfaceMulticastAddrMessage) ([]Addr, error)
var ifmat []Addr
sas, e := syscall.ParseRoutingSockaddr(m)
- if e != 0 {
+ if e != nil {
return nil, os.NewSyscallError("route sockaddr", e)
}
diff --git a/libgo/go/net/interface_linux.go b/libgo/go/net/interface_linux.go
index cd0339d61bd..96db7186af5 100644
--- a/libgo/go/net/interface_linux.go
+++ b/libgo/go/net/interface_linux.go
@@ -21,16 +21,16 @@ func interfaceTable(ifindex int) ([]Interface, error) {
ift []Interface
tab []byte
msgs []syscall.NetlinkMessage
- e int
+ e error
)
tab, e = syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)
- if e != 0 {
+ if e != nil {
return nil, os.NewSyscallError("netlink rib", e)
}
msgs, e = syscall.ParseNetlinkMessage(tab)
- if e != 0 {
+ if e != nil {
return nil, os.NewSyscallError("netlink message", e)
}
@@ -42,7 +42,7 @@ func interfaceTable(ifindex int) ([]Interface, error) {
ifim := (*syscall.IfInfomsg)(unsafe.Pointer(&m.Data[0]))
if ifindex == 0 || ifindex == int(ifim.Index) {
attrs, e := syscall.ParseNetlinkRouteAttr(&m)
- if e != 0 {
+ if e != nil {
return nil, os.NewSyscallError("netlink routeattr", e)
}
ifi := newLink(attrs, ifim)
@@ -102,27 +102,19 @@ func linkFlags(rawFlags uint32) Flags {
// for all network interfaces. Otherwise it returns addresses
// for a specific interface.
func interfaceAddrTable(ifindex int) ([]Addr, error) {
- var (
- tab []byte
- e int
- err error
- ifat []Addr
- msgs []syscall.NetlinkMessage
- )
-
- tab, e = syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC)
- if e != 0 {
+ tab, e := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC)
+ if e != nil {
return nil, os.NewSyscallError("netlink rib", e)
}
- msgs, e = syscall.ParseNetlinkMessage(tab)
- if e != 0 {
+ msgs, e := syscall.ParseNetlinkMessage(tab)
+ if e != nil {
return nil, os.NewSyscallError("netlink message", e)
}
- ifat, err = addrTable(msgs, ifindex)
- if err != nil {
- return nil, err
+ ifat, e := addrTable(msgs, ifindex)
+ if e != nil {
+ return nil, e
}
return ifat, nil
@@ -139,7 +131,7 @@ func addrTable(msgs []syscall.NetlinkMessage, ifindex int) ([]Addr, error) {
ifam := (*syscall.IfAddrmsg)(unsafe.Pointer(&m.Data[0]))
if ifindex == 0 || ifindex == int(ifam.Index) {
attrs, e := syscall.ParseNetlinkRouteAttr(&m)
- if e != 0 {
+ if e != nil {
return nil, os.NewSyscallError("netlink routeattr", e)
}
ifat = append(ifat, newAddr(attrs, int(ifam.Family))...)
diff --git a/libgo/go/net/interface_windows.go b/libgo/go/net/interface_windows.go
index a1c8d95161c..2ed66cdce37 100644
--- a/libgo/go/net/interface_windows.go
+++ b/libgo/go/net/interface_windows.go
@@ -39,7 +39,7 @@ func getAdapterList() (*syscall.IpAdapterInfo, error) {
func getInterfaceList() ([]syscall.InterfaceInfo, error) {
s, e := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP)
- if e != 0 {
+ if e != nil {
return nil, os.NewSyscallError("Socket", e)
}
defer syscall.Closesocket(s)
@@ -48,7 +48,7 @@ func getInterfaceList() ([]syscall.InterfaceInfo, error) {
ret := uint32(0)
size := uint32(unsafe.Sizeof(ii))
e = syscall.WSAIoctl(s, syscall.SIO_GET_INTERFACE_LIST, nil, 0, (*byte)(unsafe.Pointer(&ii[0])), size, &ret, nil, 0)
- if e != 0 {
+ if e != nil {
return nil, os.NewSyscallError("WSAIoctl", e)
}
c := ret / uint32(unsafe.Sizeof(ii[0]))
diff --git a/libgo/go/net/ipsock.go b/libgo/go/net/ipsock.go
index 716454d8a98..9234f5aff65 100644
--- a/libgo/go/net/ipsock.go
+++ b/libgo/go/net/ipsock.go
@@ -9,7 +9,7 @@ package net
var supportsIPv6, supportsIPv4map = probeIPv6Stack()
func firstFavoriteAddr(filter func(IP) IP, addrs []string) (addr IP) {
- if filter == anyaddr {
+ if filter == nil {
// We'll take any IP address, but since the dialing code
// does not yet try multiple addresses, prefer to use
// an IPv4 address if possible. This is especially relevant
@@ -113,7 +113,7 @@ func hostPortToIP(net, hostport string) (ip IP, iport int, err error) {
// Try as an IP address.
addr = ParseIP(host)
if addr == nil {
- filter := anyaddr
+ var filter func(IP) IP
if net != "" && net[len(net)-1] == '4' {
filter = ipv4only
}
diff --git a/libgo/go/net/ipsock_posix.go b/libgo/go/net/ipsock_posix.go
index d5b8f2189c4..f0ca7dad345 100644
--- a/libgo/go/net/ipsock_posix.go
+++ b/libgo/go/net/ipsock_posix.go
@@ -33,8 +33,8 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
}
for i := range probes {
- s, errno := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
- if errno != 0 {
+ s, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
+ if err != nil {
continue
}
defer closesocket(s)
@@ -42,8 +42,8 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
if err != nil {
continue
}
- errno = syscall.Bind(s, sa)
- if errno != 0 {
+ err = syscall.Bind(s, sa)
+ if err != nil {
continue
}
probes[i].ok = true
diff --git a/libgo/go/net/lookup_windows.go b/libgo/go/net/lookup_windows.go
index 61d8a8871e1..020871b46d6 100644
--- a/libgo/go/net/lookup_windows.go
+++ b/libgo/go/net/lookup_windows.go
@@ -22,7 +22,7 @@ func lookupProtocol(name string) (proto int, err error) {
protoentLock.Lock()
defer protoentLock.Unlock()
p, e := syscall.GetProtoByName(name)
- if e != 0 {
+ if e != nil {
return 0, os.NewSyscallError("GetProtoByName", e)
}
return int(p.Proto), nil
@@ -44,7 +44,7 @@ func LookupIP(name string) (addrs []IP, err error) {
hostentLock.Lock()
defer hostentLock.Unlock()
h, e := syscall.GetHostByName(name)
- if e != 0 {
+ if e != nil {
return nil, os.NewSyscallError("GetHostByName", e)
}
switch h.AddrType {
@@ -71,7 +71,7 @@ func LookupPort(network, service string) (port int, err error) {
serventLock.Lock()
defer serventLock.Unlock()
s, e := syscall.GetServByName(service, network)
- if e != 0 {
+ if e != nil {
return 0, os.NewSyscallError("GetServByName", e)
}
return int(syscall.Ntohs(s.Port)), nil
@@ -81,7 +81,7 @@ func LookupCNAME(name string) (cname string, err error) {
var r *syscall.DNSRecord
e := syscall.DnsQuery(name, syscall.DNS_TYPE_CNAME, 0, nil, &r, nil)
if e != 0 {
- return "", os.NewSyscallError("LookupCNAME", int(e))
+ return "", os.NewSyscallError("LookupCNAME", e)
}
defer syscall.DnsRecordListFree(r, 1)
if r != nil && r.Type == syscall.DNS_TYPE_CNAME {
@@ -110,7 +110,7 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err err
var r *syscall.DNSRecord
e := syscall.DnsQuery(target, syscall.DNS_TYPE_SRV, 0, nil, &r, nil)
if e != 0 {
- return "", nil, os.NewSyscallError("LookupSRV", int(e))
+ return "", nil, os.NewSyscallError("LookupSRV", e)
}
defer syscall.DnsRecordListFree(r, 1)
addrs = make([]*SRV, 0, 10)
@@ -126,7 +126,7 @@ func LookupMX(name string) (mx []*MX, err error) {
var r *syscall.DNSRecord
e := syscall.DnsQuery(name, syscall.DNS_TYPE_MX, 0, nil, &r, nil)
if e != 0 {
- return nil, os.NewSyscallError("LookupMX", int(e))
+ return nil, os.NewSyscallError("LookupMX", e)
}
defer syscall.DnsRecordListFree(r, 1)
mx = make([]*MX, 0, 10)
@@ -142,7 +142,7 @@ func LookupTXT(name string) (txt []string, err error) {
var r *syscall.DNSRecord
e := syscall.DnsQuery(name, syscall.DNS_TYPE_TEXT, 0, nil, &r, nil)
if e != 0 {
- return nil, os.NewSyscallError("LookupTXT", int(e))
+ return nil, os.NewSyscallError("LookupTXT", e)
}
defer syscall.DnsRecordListFree(r, 1)
txt = make([]string, 0, 10)
@@ -164,7 +164,7 @@ func LookupAddr(addr string) (name []string, err error) {
var r *syscall.DNSRecord
e := syscall.DnsQuery(arpa, syscall.DNS_TYPE_PTR, 0, nil, &r, nil)
if e != 0 {
- return nil, os.NewSyscallError("LookupAddr", int(e))
+ return nil, os.NewSyscallError("LookupAddr", e)
}
defer syscall.DnsRecordListFree(r, 1)
name = make([]string, 0, 10)
diff --git a/libgo/go/net/newpollserver.go b/libgo/go/net/newpollserver.go
index 9ad6f7ba276..035df4a6ff1 100644
--- a/libgo/go/net/newpollserver.go
+++ b/libgo/go/net/newpollserver.go
@@ -18,11 +18,10 @@ func newPollServer() (s *pollServer, err error) {
if s.pr, s.pw, err = os.Pipe(); err != nil {
return nil, err
}
- var e int
- if e = syscall.SetNonblock(s.pr.Fd(), true); e != 0 {
+ if err = syscall.SetNonblock(s.pr.Fd(), true); err != nil {
goto Errno
}
- if e = syscall.SetNonblock(s.pw.Fd(), true); e != 0 {
+ if err = syscall.SetNonblock(s.pw.Fd(), true); err != nil {
goto Errno
}
if s.poll, err = newpollster(); err != nil {
@@ -37,7 +36,7 @@ func newPollServer() (s *pollServer, err error) {
return s, nil
Errno:
- err = &os.PathError{"setnonblock", s.pr.Name(), os.Errno(e)}
+ err = &os.PathError{"setnonblock", s.pr.Name(), err}
Error:
s.pr.Close()
s.pw.Close()
diff --git a/libgo/go/net/pipe.go b/libgo/go/net/pipe.go
index b99e6e658de..0ce7ccb9d7b 100644
--- a/libgo/go/net/pipe.go
+++ b/libgo/go/net/pipe.go
@@ -1,3 +1,7 @@
+// Copyright 2010 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 (
diff --git a/libgo/go/net/sendfile_linux.go b/libgo/go/net/sendfile_linux.go
index 36c75785789..350abe451f3 100644
--- a/libgo/go/net/sendfile_linux.go
+++ b/libgo/go/net/sendfile_linux.go
@@ -62,18 +62,18 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
written += int64(n)
remain -= int64(n)
}
- if n == 0 && errno == 0 {
+ if n == 0 && errno == nil {
break
}
if errno == syscall.EAGAIN && c.wdeadline >= 0 {
pollserver.WaitWrite(c)
continue
}
- if errno != 0 {
+ if errno != nil {
// This includes syscall.ENOSYS (no kernel
// support) and syscall.EINVAL (fd types which
// don't implement sendfile together)
- err = &OpError{"sendfile", c.net, c.raddr, os.Errno(errno)}
+ err = &OpError{"sendfile", c.net, c.raddr, errno}
break
}
}
diff --git a/libgo/go/net/sendfile_windows.go b/libgo/go/net/sendfile_windows.go
index 0b31572771c..ee7ff8b98c2 100644
--- a/libgo/go/net/sendfile_windows.go
+++ b/libgo/go/net/sendfile_windows.go
@@ -16,7 +16,7 @@ type sendfileOp struct {
n uint32
}
-func (o *sendfileOp) Submit() (errno int) {
+func (o *sendfileOp) Submit() (err error) {
return syscall.TransmitFile(o.fd.sysfd, o.src, o.n, 0, &o.o, nil, syscall.TF_WRITE_BEHIND)
}
diff --git a/libgo/go/net/sock.go b/libgo/go/net/sock.go
index d9df02cd63f..33f11f219c9 100644
--- a/libgo/go/net/sock.go
+++ b/libgo/go/net/sock.go
@@ -28,9 +28,9 @@ func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscal
// See ../syscall/exec.go for description of ForkLock.
syscall.ForkLock.RLock()
s, e := syscall.Socket(f, p, t)
- if e != 0 {
+ if err != nil {
syscall.ForkLock.RUnlock()
- return nil, os.Errno(e)
+ return nil, err
}
syscall.CloseOnExec(s)
syscall.ForkLock.RUnlock()
@@ -39,9 +39,9 @@ func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscal
if la != nil {
e = syscall.Bind(s, la)
- if e != 0 {
+ if e != nil {
closesocket(s)
- return nil, os.Errno(e)
+ return nil, e
}
}
diff --git a/libgo/go/net/tcpsock_posix.go b/libgo/go/net/tcpsock_posix.go
index a726b45c15a..44890ba66bb 100644
--- a/libgo/go/net/tcpsock_posix.go
+++ b/libgo/go/net/tcpsock_posix.go
@@ -250,9 +250,9 @@ func ListenTCP(net string, laddr *TCPAddr) (l *TCPListener, err error) {
return nil, err
}
errno := syscall.Listen(fd.sysfd, listenBacklog())
- if errno != 0 {
+ if errno != nil {
closesocket(fd.sysfd)
- return nil, &OpError{"listen", "tcp", laddr, os.Errno(errno)}
+ return nil, &OpError{"listen", "tcp", laddr, errno}
}
l = new(TCPListener)
l.fd = fd
diff --git a/libgo/go/net/unixsock_posix.go b/libgo/go/net/unixsock_posix.go
index 6ba692e5083..929f6409a4f 100644
--- a/libgo/go/net/unixsock_posix.go
+++ b/libgo/go/net/unixsock_posix.go
@@ -327,9 +327,9 @@ func ListenUnix(net string, laddr *UnixAddr) (l *UnixListener, err error) {
return nil, err
}
e1 := syscall.Listen(fd.sysfd, 8) // listenBacklog());
- if e1 != 0 {
+ if e1 != nil {
closesocket(fd.sysfd)
- return nil, &OpError{Op: "listen", Net: "unix", Addr: laddr, Err: os.Errno(e1)}
+ return nil, &OpError{Op: "listen", Net: "unix", Addr: laddr, Err: e1}
}
return &UnixListener{fd, laddr.Name}, nil
}
diff --git a/libgo/go/os/dir_largefile.go b/libgo/go/os/dir_largefile.go
index c723ec92400..d6b4239610e 100644
--- a/libgo/go/os/dir_largefile.go
+++ b/libgo/go/os/dir_largefile.go
@@ -9,4 +9,4 @@ package os
import "syscall"
-func libc_readdir_r(*syscall.DIR, *syscall.Dirent, **syscall.Dirent) int __asm__ ("readdir64_r")
+func libc_readdir_r(*syscall.DIR, *syscall.Dirent, **syscall.Dirent) syscall.Errno __asm__ ("readdir64_r")
diff --git a/libgo/go/os/dir_regfile.go b/libgo/go/os/dir_regfile.go
index 22fb5febbb2..7effdf7851a 100644
--- a/libgo/go/os/dir_regfile.go
+++ b/libgo/go/os/dir_regfile.go
@@ -9,4 +9,4 @@ package os
import "syscall"
-func libc_readdir_r(*syscall.DIR, *syscall.Dirent, **syscall.Dirent) int __asm__ ("readdir_r")
+func libc_readdir_r(*syscall.DIR, *syscall.Dirent, **syscall.Dirent) syscall.Errno __asm__ ("readdir_r")
diff --git a/libgo/go/os/dir_unix.go b/libgo/go/os/dir_unix.go
index a16bcf63f41..e4dff835d89 100644
--- a/libgo/go/os/dir_unix.go
+++ b/libgo/go/os/dir_unix.go
@@ -47,9 +47,9 @@ func (f *File) Readdirnames(n int) (names []string, err error) {
// Refill the buffer if necessary
if d.bufp >= d.nbuf {
d.bufp = 0
- var errno int
+ var errno error
d.nbuf, errno = syscall.ReadDirent(f.fd, d.buf)
- if errno != 0 {
+ if errno != nil {
return names, NewSyscallError("readdirent", errno)
}
if d.nbuf <= 0 {
diff --git a/libgo/go/os/env.go b/libgo/go/os/env.go
index 4844fa3e26d..7e3f52502e5 100644
--- a/libgo/go/os/env.go
+++ b/libgo/go/os/env.go
@@ -6,7 +6,10 @@
package os
-func setenv_c(k, v string)
+import (
+ "errors"
+ "syscall"
+)
// Expand replaces ${var} or $var in the string based on the mapping function.
// Invocations of undefined variables are replaced with the empty string.
@@ -73,3 +76,47 @@ func getShellName(s string) (string, int) {
}
return s[:i], i
}
+
+// ENOENV is the error indicating that an environment variable does not exist.
+var ENOENV = errors.New("no such environment variable")
+
+// Getenverror retrieves the value of the environment variable named by the key.
+// It returns the value and an error, if any.
+func Getenverror(key string) (value string, err error) {
+ if len(key) == 0 {
+ return "", EINVAL
+ }
+ val, found := syscall.Getenv(key)
+ if !found {
+ return "", ENOENV
+ }
+ return val, nil
+}
+
+// Getenv retrieves the value of the environment variable named by the key.
+// It returns the value, which will be empty if the variable is not present.
+func Getenv(key string) string {
+ v, _ := Getenverror(key)
+ return v
+}
+
+// Setenv sets the value of the environment variable named by the key.
+// It returns an error, if any.
+func Setenv(key, value string) error {
+ err := syscall.Setenv(key, value)
+ if err != nil {
+ return NewSyscallError("setenv", err)
+ }
+ return nil
+}
+
+// Clearenv deletes all environment variables.
+func Clearenv() {
+ syscall.Clearenv()
+}
+
+// Environ returns an array of strings representing the environment,
+// in the form "key=value".
+func Environ() []string {
+ return syscall.Environ()
+}
diff --git a/libgo/go/os/env_plan9.go b/libgo/go/os/env_plan9.go
deleted file mode 100644
index 9757aa902af..00000000000
--- a/libgo/go/os/env_plan9.go
+++ /dev/null
@@ -1,99 +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.
-
-// Plan 9 environment variables.
-
-package os
-
-import (
- "errors"
- "syscall"
-)
-
-// ENOENV is the error indicating that an environment variable does not exist.
-var ENOENV = errors.New("no such environment variable")
-
-// Getenverror retrieves the value of the environment variable named by the key.
-// It returns the value and an error, if any.
-func Getenverror(key string) (value string, err error) {
- if len(key) == 0 {
- return "", EINVAL
- }
- f, e := Open("/env/" + key)
- if iserror(e) {
- return "", ENOENV
- }
- defer f.Close()
-
- l, _ := f.Seek(0, 2)
- f.Seek(0, 0)
- buf := make([]byte, l)
- n, e := f.Read(buf)
- if iserror(e) {
- return "", ENOENV
- }
-
- if n > 0 && buf[n-1] == 0 {
- buf = buf[:n-1]
- }
- return string(buf), nil
-}
-
-// Getenv retrieves the value of the environment variable named by the key.
-// It returns the value, which will be empty if the variable is not present.
-func Getenv(key string) string {
- v, _ := Getenverror(key)
- return v
-}
-
-// Setenv sets the value of the environment variable named by the key.
-// It returns an error, if any.
-func Setenv(key, value string) error {
- if len(key) == 0 {
- return EINVAL
- }
-
- f, e := Create("/env/" + key)
- if iserror(e) {
- return e
- }
- defer f.Close()
-
- _, e = f.Write([]byte(value))
- return nil
-}
-
-// Clearenv deletes all environment variables.
-func Clearenv() {
- syscall.RawSyscall(syscall.SYS_RFORK, syscall.RFCENVG, 0, 0)
-}
-
-// Environ returns an array of strings representing the environment,
-// in the form "key=value".
-func Environ() []string {
- env := make([]string, 0, 100)
-
- f, e := Open("/env")
- if iserror(e) {
- panic(e)
- }
- defer f.Close()
-
- names, e := f.Readdirnames(-1)
- if iserror(e) {
- panic(e)
- }
-
- for _, k := range names {
- if v, e := Getenverror(k); !iserror(e) {
- env = append(env, k+"="+v)
- }
- }
- return env[0:len(env)]
-}
-
-// TempDir returns the default directory to use for temporary files.
-func TempDir() string {
- return "/tmp"
-}
diff --git a/libgo/go/os/env_unix.go b/libgo/go/os/env_unix.go
deleted file mode 100644
index 01fd9d449f3..00000000000
--- a/libgo/go/os/env_unix.go
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build darwin freebsd linux openbsd
-
-// Unix environment variables.
-
-package os
-
-import (
- "errors"
- "sync"
-)
-
-// ENOENV is the error indicating that an environment variable does not exist.
-var ENOENV = errors.New("no such environment variable")
-
-var env map[string]string
-var once sync.Once
-
-func copyenv() {
- env = make(map[string]string)
- for _, s := range Envs {
- for j := 0; j < len(s); j++ {
- if s[j] == '=' {
- env[s[0:j]] = s[j+1:]
- break
- }
- }
- }
-}
-
-var envLock sync.RWMutex
-
-// Getenverror retrieves the value of the environment variable named by the key.
-// It returns the value and an error, if any.
-func Getenverror(key string) (value string, err error) {
- once.Do(copyenv)
-
- if len(key) == 0 {
- return "", EINVAL
- }
-
- envLock.RLock()
- defer envLock.RUnlock()
-
- v, ok := env[key]
- if !ok {
- return "", ENOENV
- }
- return v, nil
-}
-
-// Getenv retrieves the value of the environment variable named by the key.
-// It returns the value, which will be empty if the variable is not present.
-func Getenv(key string) string {
- v, _ := Getenverror(key)
- return v
-}
-
-// Setenv sets the value of the environment variable named by the key.
-// It returns an error, if any.
-func Setenv(key, value string) error {
- once.Do(copyenv)
- if len(key) == 0 {
- return EINVAL
- }
-
- envLock.Lock()
- defer envLock.Unlock()
-
- env[key] = value
- setenv_c(key, value) // is a no-op if cgo isn't loaded
- return nil
-}
-
-// Clearenv deletes all environment variables.
-func Clearenv() {
- once.Do(copyenv) // prevent copyenv in Getenv/Setenv
-
- envLock.Lock()
- defer envLock.Unlock()
-
- env = make(map[string]string)
-
- // TODO(bradfitz): pass through to C
-}
-
-// Environ returns an array of strings representing the environment,
-// in the form "key=value".
-func Environ() []string {
- once.Do(copyenv)
- envLock.RLock()
- defer envLock.RUnlock()
- a := make([]string, len(env))
- i := 0
- for k, v := range env {
- a[i] = k + "=" + v
- i++
- }
- return a
-}
-
-// TempDir returns the default directory to use for temporary files.
-func TempDir() string {
- dir := Getenv("TMPDIR")
- if dir == "" {
- dir = "/tmp"
- }
- return dir
-}
diff --git a/libgo/go/os/env_windows.go b/libgo/go/os/env_windows.go
deleted file mode 100644
index 4e90385da96..00000000000
--- a/libgo/go/os/env_windows.go
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright 2010 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.
-
-// Windows environment variables.
-
-package os
-
-import (
- "errors"
- "syscall"
- "unicode/utf16"
- "unsafe"
-)
-
-// ENOENV is the error indicating that an environment variable does not exist.
-var ENOENV = errors.New("no such environment variable")
-
-// Getenverror retrieves the value of the environment variable named by the key.
-// It returns the value and an error, if any.
-func Getenverror(key string) (value string, err error) {
- b := make([]uint16, 100)
- n, e := syscall.GetEnvironmentVariable(syscall.StringToUTF16Ptr(key), &b[0], uint32(len(b)))
- if n == 0 && e == syscall.ERROR_ENVVAR_NOT_FOUND {
- return "", ENOENV
- }
- if n > uint32(len(b)) {
- b = make([]uint16, n)
- n, e = syscall.GetEnvironmentVariable(syscall.StringToUTF16Ptr(key), &b[0], uint32(len(b)))
- if n > uint32(len(b)) {
- n = 0
- }
- }
- if n == 0 {
- return "", NewSyscallError("GetEnvironmentVariable", e)
- }
- return string(utf16.Decode(b[0:n])), nil
-}
-
-// Getenv retrieves the value of the environment variable named by the key.
-// It returns the value, which will be empty if the variable is not present.
-func Getenv(key string) string {
- v, _ := Getenverror(key)
- return v
-}
-
-// Setenv sets the value of the environment variable named by the key.
-// It returns an error, if any.
-func Setenv(key, value string) error {
- var v *uint16
- if len(value) > 0 {
- v = syscall.StringToUTF16Ptr(value)
- }
- e := syscall.SetEnvironmentVariable(syscall.StringToUTF16Ptr(key), v)
- if e != 0 {
- return NewSyscallError("SetEnvironmentVariable", e)
- }
- return nil
-}
-
-// Clearenv deletes all environment variables.
-func Clearenv() {
- for _, s := range Environ() {
- // Environment variables can begin with =
- // so start looking for the separator = at j=1.
- // http://blogs.msdn.com/b/oldnewthing/archive/2010/05/06/10008132.aspx
- for j := 1; j < len(s); j++ {
- if s[j] == '=' {
- Setenv(s[0:j], "")
- break
- }
- }
- }
-}
-
-// Environ returns an array of strings representing the environment,
-// in the form "key=value".
-func Environ() []string {
- s, e := syscall.GetEnvironmentStrings()
- if e != 0 {
- return nil
- }
- defer syscall.FreeEnvironmentStrings(s)
- r := make([]string, 0, 50) // Empty with room to grow.
- for from, i, p := 0, 0, (*[1 << 24]uint16)(unsafe.Pointer(s)); true; i++ {
- if p[i] == 0 {
- // empty string marks the end
- if i <= from {
- break
- }
- r = append(r, string(utf16.Decode(p[from:i])))
- from = i + 1
- }
- }
- return r
-}
-
-// TempDir returns the default directory to use for temporary files.
-func TempDir() string {
- const pathSep = '\\'
- dirw := make([]uint16, syscall.MAX_PATH)
- n, _ := syscall.GetTempPath(uint32(len(dirw)), &dirw[0])
- if n > uint32(len(dirw)) {
- dirw = make([]uint16, n)
- n, _ = syscall.GetTempPath(uint32(len(dirw)), &dirw[0])
- if n > uint32(len(dirw)) {
- n = 0
- }
- }
- if n > 0 && dirw[n-1] == pathSep {
- n--
- }
- return string(utf16.Decode(dirw[0:n]))
-}
-
-func init() {
- var argc int32
- cmd := syscall.GetCommandLine()
- argv, e := syscall.CommandLineToArgv(cmd, &argc)
- if e != 0 {
- return
- }
- defer syscall.LocalFree(syscall.Handle(uintptr(unsafe.Pointer(argv))))
- Args = make([]string, argc)
- for i, v := range (*argv)[:argc] {
- Args[i] = string(syscall.UTF16ToString((*v)[:]))
- }
-}
diff --git a/libgo/go/os/error_plan9.go b/libgo/go/os/error_plan9.go
index e08707078ec..8f005efbe05 100644
--- a/libgo/go/os/error_plan9.go
+++ b/libgo/go/os/error_plan9.go
@@ -24,7 +24,7 @@ func (e *SyscallError) Error() string { return e.Syscall + ": " + e.Err }
// NewSyscallError returns, as an error, a new SyscallError
// with the given system call name and error details.
// As a convenience, if err is nil, NewSyscallError returns nil.
-func NewSyscallError(syscall string, err syscall.Error) error {
+func NewSyscallError(syscall string, err error) error {
if err == nil {
return nil
}
@@ -57,9 +57,3 @@ var (
EPIPE = errors.New("Broken Pipe")
EPLAN9 = errors.New("not supported by plan 9")
)
-
-func iserror(err syscall.Error) bool {
- return err != nil
-}
-
-func Errno(e syscall.Error) syscall.Error { return e }
diff --git a/libgo/go/os/error_posix.go b/libgo/go/os/error_posix.go
index c3d79425062..dbe1b9a8d5e 100644
--- a/libgo/go/os/error_posix.go
+++ b/libgo/go/os/error_posix.go
@@ -8,67 +8,53 @@ package os
import syscall "syscall"
-// Errno is the Unix error number. Names such as EINVAL are simple
-// wrappers to convert the error number into an error.
-type Errno int64
-
-func (e Errno) Error() string { return syscall.Errstr(int(e)) }
-
-func (e Errno) Temporary() bool {
- return e == Errno(syscall.EINTR) || e == Errno(syscall.EMFILE) || e.Timeout()
-}
-
-func (e Errno) Timeout() bool {
- return e == Errno(syscall.EAGAIN) || e == Errno(syscall.EWOULDBLOCK) || e == Errno(syscall.ETIMEDOUT)
-}
-
// Commonly known Unix errors.
var (
- EPERM error = Errno(syscall.EPERM)
- ENOENT error = Errno(syscall.ENOENT)
- ESRCH error = Errno(syscall.ESRCH)
- EINTR error = Errno(syscall.EINTR)
- EIO error = Errno(syscall.EIO)
- ENXIO error = Errno(syscall.ENXIO)
- E2BIG error = Errno(syscall.E2BIG)
- ENOEXEC error = Errno(syscall.ENOEXEC)
- EBADF error = Errno(syscall.EBADF)
- ECHILD error = Errno(syscall.ECHILD)
- EDEADLK error = Errno(syscall.EDEADLK)
- ENOMEM error = Errno(syscall.ENOMEM)
- EACCES error = Errno(syscall.EACCES)
- EFAULT error = Errno(syscall.EFAULT)
- EBUSY error = Errno(syscall.EBUSY)
- EEXIST error = Errno(syscall.EEXIST)
- EXDEV error = Errno(syscall.EXDEV)
- ENODEV error = Errno(syscall.ENODEV)
- ENOTDIR error = Errno(syscall.ENOTDIR)
- EISDIR error = Errno(syscall.EISDIR)
- EINVAL error = Errno(syscall.EINVAL)
- ENFILE error = Errno(syscall.ENFILE)
- EMFILE error = Errno(syscall.EMFILE)
- ENOTTY error = Errno(syscall.ENOTTY)
- EFBIG error = Errno(syscall.EFBIG)
- ENOSPC error = Errno(syscall.ENOSPC)
- ESPIPE error = Errno(syscall.ESPIPE)
- EROFS error = Errno(syscall.EROFS)
- EMLINK error = Errno(syscall.EMLINK)
- EPIPE error = Errno(syscall.EPIPE)
- EAGAIN error = Errno(syscall.EAGAIN)
- EDOM error = Errno(syscall.EDOM)
- ERANGE error = Errno(syscall.ERANGE)
- EADDRINUSE error = Errno(syscall.EADDRINUSE)
- ECONNREFUSED error = Errno(syscall.ECONNREFUSED)
- ENAMETOOLONG error = Errno(syscall.ENAMETOOLONG)
- EAFNOSUPPORT error = Errno(syscall.EAFNOSUPPORT)
- ETIMEDOUT error = Errno(syscall.ETIMEDOUT)
- ENOTCONN error = Errno(syscall.ENOTCONN)
+ EPERM error = syscall.EPERM
+ ENOENT error = syscall.ENOENT
+ ESRCH error = syscall.ESRCH
+ EINTR error = syscall.EINTR
+ EIO error = syscall.EIO
+ ENXIO error = syscall.ENXIO
+ E2BIG error = syscall.E2BIG
+ ENOEXEC error = syscall.ENOEXEC
+ EBADF error = syscall.EBADF
+ ECHILD error = syscall.ECHILD
+ EDEADLK error = syscall.EDEADLK
+ ENOMEM error = syscall.ENOMEM
+ EACCES error = syscall.EACCES
+ EFAULT error = syscall.EFAULT
+ EBUSY error = syscall.EBUSY
+ EEXIST error = syscall.EEXIST
+ EXDEV error = syscall.EXDEV
+ ENODEV error = syscall.ENODEV
+ ENOTDIR error = syscall.ENOTDIR
+ EISDIR error = syscall.EISDIR
+ EINVAL error = syscall.EINVAL
+ ENFILE error = syscall.ENFILE
+ EMFILE error = syscall.EMFILE
+ ENOTTY error = syscall.ENOTTY
+ EFBIG error = syscall.EFBIG
+ ENOSPC error = syscall.ENOSPC
+ ESPIPE error = syscall.ESPIPE
+ EROFS error = syscall.EROFS
+ EMLINK error = syscall.EMLINK
+ EPIPE error = syscall.EPIPE
+ EAGAIN error = syscall.EAGAIN
+ EDOM error = syscall.EDOM
+ ERANGE error = syscall.ERANGE
+ EADDRINUSE error = syscall.EADDRINUSE
+ ECONNREFUSED error = syscall.ECONNREFUSED
+ ENAMETOOLONG error = syscall.ENAMETOOLONG
+ EAFNOSUPPORT error = syscall.EAFNOSUPPORT
+ ETIMEDOUT error = syscall.ETIMEDOUT
+ ENOTCONN error = syscall.ENOTCONN
)
// SyscallError records an error from a specific system call.
type SyscallError struct {
Syscall string
- Errno Errno
+ Errno error
}
func (e *SyscallError) Error() string { return e.Syscall + ": " + e.Errno.Error() }
@@ -79,14 +65,10 @@ func (e *SyscallError) Error() string { return e.Syscall + ": " + e.Errno.Error(
// NewSyscallError returns, as an error, a new SyscallError
// with the given system call name and error details.
-// As a convenience, if errno is 0, NewSyscallError returns nil.
-func NewSyscallError(syscall string, errno int) error {
- if errno == 0 {
+// As a convenience, if err is nil, NewSyscallError returns nil.
+func NewSyscallError(syscall string, err error) error {
+ if err == nil {
return nil
}
- return &SyscallError{syscall, Errno(errno)}
-}
-
-func iserror(errno int) bool {
- return errno != 0
+ return &SyscallError{syscall, err}
}
diff --git a/libgo/go/os/exec/exec.go b/libgo/go/os/exec/exec.go
index ebdfd54a734..4c95c1b0dac 100644
--- a/libgo/go/os/exec/exec.go
+++ b/libgo/go/os/exec/exec.go
@@ -50,14 +50,14 @@ type Cmd struct {
// calling process's current directory.
Dir string
- // Stdin specifies the process's standard input.
- // If Stdin is nil, the process reads from DevNull.
+ // Stdin specifies the process's standard input. If Stdin is
+ // nil, the process reads from the null device (os.DevNull).
Stdin io.Reader
// Stdout and Stderr specify the process's standard output and error.
//
- // If either is nil, Run connects the
- // corresponding file descriptor to /dev/null.
+ // If either is nil, Run connects the corresponding file descriptor
+ // to the null device (os.DevNull).
//
// If Stdout and Stderr are are the same writer, at most one
// goroutine at a time will call Write.
diff --git a/libgo/go/os/exec_plan9.go b/libgo/go/os/exec_plan9.go
index a1a335359dc..9a0db6dd3ef 100644
--- a/libgo/go/os/exec_plan9.go
+++ b/libgo/go/os/exec_plan9.go
@@ -32,7 +32,7 @@ func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err e
sysattr.Files = intfd
pid, h, e := syscall.StartProcess(name, argv, sysattr)
- if iserror(e) {
+ if e != nil {
return nil, &PathError{"fork/exec", name, e}
}
@@ -52,7 +52,7 @@ func (p *Process) Signal(sig Signal) error {
}
f, e := OpenFile("/proc/"+itoa(p.Pid)+"/note", O_WRONLY, 0)
- if iserror(e) {
+ if e != nil {
return NewSyscallError("signal", e)
}
defer f.Close()
@@ -63,7 +63,7 @@ func (p *Process) Signal(sig Signal) error {
// Kill causes the Process to exit immediately.
func (p *Process) Kill() error {
f, e := OpenFile("/proc/"+itoa(p.Pid)+"/ctl", O_WRONLY, 0)
- if iserror(e) {
+ if e != nil {
return NewSyscallError("kill", e)
}
defer f.Close()
@@ -77,7 +77,7 @@ func (p *Process) Kill() error {
// ForkExec is almost always a better way to execute a program.
func Exec(name string, argv []string, envv []string) error {
e := syscall.Exec(name, argv, envv)
- if iserror(e) {
+ if e != nil {
return &PathError{"exec", name, e}
}
@@ -102,7 +102,7 @@ func (p *Process) Wait(options int) (w *Waitmsg, err error) {
for true {
err = syscall.Await(&waitmsg)
- if iserror(err) {
+ if err != nil {
return nil, NewSyscallError("wait", err)
}
diff --git a/libgo/go/os/exec_posix.go b/libgo/go/os/exec_posix.go
index 12b44e5f33b..8b08eebd0da 100644
--- a/libgo/go/os/exec_posix.go
+++ b/libgo/go/os/exec_posix.go
@@ -40,8 +40,8 @@ func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err e
}
pid, h, e := syscall.StartProcess(name, argv, sysattr)
- if iserror(e) {
- return nil, &PathError{"fork/exec", name, Errno(e)}
+ if e != nil {
+ return nil, &PathError{"fork/exec", name, e}
}
return newProcess(pid, h), nil
}
@@ -62,8 +62,8 @@ func Exec(name string, argv []string, envv []string) error {
envv = Environ()
}
e := syscall.Exec(name, argv, envv)
- if iserror(e) {
- return &PathError{"exec", name, Errno(e)}
+ if e != nil {
+ return &PathError{"exec", name, e}
}
return nil
}
diff --git a/libgo/go/os/exec_unix.go b/libgo/go/os/exec_unix.go
index 242bda702c6..3dcac414c5a 100644
--- a/libgo/go/os/exec_unix.go
+++ b/libgo/go/os/exec_unix.go
@@ -38,7 +38,7 @@ func (p *Process) Wait(options int) (w *Waitmsg, err error) {
options ^= WRUSAGE
}
pid1, e := syscall.Wait4(p.Pid, &status, options, rusage)
- if e != 0 {
+ if e != nil {
return nil, NewSyscallError("wait", e)
}
// With WNOHANG pid is 0 if child has not exited.
@@ -57,8 +57,8 @@ func (p *Process) Signal(sig Signal) error {
if p.done {
return errors.New("os: process already finished")
}
- if e := syscall.Kill(p.Pid, int(sig.(UnixSignal))); e != 0 {
- return Errno(e)
+ if e := syscall.Kill(p.Pid, int(sig.(UnixSignal))); e != nil {
+ return e
}
return nil
}
diff --git a/libgo/go/os/exec_windows.go b/libgo/go/os/exec_windows.go
index 866757e3129..c4c9dcfe829 100644
--- a/libgo/go/os/exec_windows.go
+++ b/libgo/go/os/exec_windows.go
@@ -8,6 +8,7 @@ import (
"errors"
"runtime"
"syscall"
+ "unsafe"
)
func (p *Process) Wait(options int) (w *Waitmsg, err error) {
@@ -22,7 +23,7 @@ func (p *Process) Wait(options int) (w *Waitmsg, err error) {
}
var ec uint32
e = syscall.GetExitCodeProcess(syscall.Handle(p.handle), &ec)
- if e != 0 {
+ if e != nil {
return nil, NewSyscallError("GetExitCodeProcess", e)
}
p.done = true
@@ -39,7 +40,7 @@ func (p *Process) Signal(sig Signal) error {
e := syscall.TerminateProcess(syscall.Handle(p.handle), 1)
return NewSyscallError("TerminateProcess", e)
}
- return Errno(syscall.EWINDOWS)
+ return syscall.Errno(syscall.EWINDOWS)
}
func (p *Process) Release() error {
@@ -47,7 +48,7 @@ func (p *Process) Release() error {
return EINVAL
}
e := syscall.CloseHandle(syscall.Handle(p.handle))
- if e != 0 {
+ if e != nil {
return NewSyscallError("CloseHandle", e)
}
p.handle = -1
@@ -60,8 +61,22 @@ func FindProcess(pid int) (p *Process, err error) {
const da = syscall.STANDARD_RIGHTS_READ |
syscall.PROCESS_QUERY_INFORMATION | syscall.SYNCHRONIZE
h, e := syscall.OpenProcess(da, false, uint32(pid))
- if e != 0 {
+ if e != nil {
return nil, NewSyscallError("OpenProcess", e)
}
return newProcess(pid, int(h)), nil
}
+
+func init() {
+ var argc int32
+ cmd := syscall.GetCommandLine()
+ argv, e := syscall.CommandLineToArgv(cmd, &argc)
+ if e != nil {
+ return
+ }
+ defer syscall.LocalFree(syscall.Handle(uintptr(unsafe.Pointer(argv))))
+ Args = make([]string, argc)
+ for i, v := range (*argv)[:argc] {
+ Args[i] = string(syscall.UTF16ToString((*v)[:]))
+ }
+}
diff --git a/libgo/go/os/file.go b/libgo/go/os/file.go
index 0f3b2db7ea2..386afb889b2 100644
--- a/libgo/go/os/file.go
+++ b/libgo/go/os/file.go
@@ -59,11 +59,11 @@ func (file *File) Read(b []byte) (n int, err error) {
if n < 0 {
n = 0
}
- if n == 0 && len(b) > 0 && !iserror(e) {
+ if n == 0 && len(b) > 0 && e == nil {
return 0, io.EOF
}
- if iserror(e) {
- err = &PathError{"read", file.name, Errno(e)}
+ if e != nil {
+ err = &PathError{"read", file.name, e}
}
return n, err
}
@@ -78,11 +78,11 @@ func (file *File) ReadAt(b []byte, off int64) (n int, err error) {
}
for len(b) > 0 {
m, e := file.pread(b, off)
- if m == 0 && !iserror(e) {
+ if m == 0 && e == nil {
return n, io.EOF
}
- if iserror(e) {
- err = &PathError{"read", file.name, Errno(e)}
+ if e != nil {
+ err = &PathError{"read", file.name, e}
break
}
n += m
@@ -106,8 +106,8 @@ func (file *File) Write(b []byte) (n int, err error) {
epipecheck(file, e)
- if iserror(e) {
- err = &PathError{"write", file.name, Errno(e)}
+ if e != nil {
+ err = &PathError{"write", file.name, e}
}
return n, err
}
@@ -121,8 +121,8 @@ func (file *File) WriteAt(b []byte, off int64) (n int, err error) {
}
for len(b) > 0 {
m, e := file.pwrite(b, off)
- if iserror(e) {
- err = &PathError{"write", file.name, Errno(e)}
+ if e != nil {
+ err = &PathError{"write", file.name, e}
break
}
n += m
@@ -138,11 +138,11 @@ func (file *File) WriteAt(b []byte, off int64) (n int, err error) {
// It returns the new offset and an error, if any.
func (file *File) Seek(offset int64, whence int) (ret int64, err error) {
r, e := file.seek(offset, whence)
- if !iserror(e) && file.dirinfo != nil && r != 0 {
+ if e == nil && file.dirinfo != nil && r != 0 {
e = syscall.EISDIR
}
- if iserror(e) {
- return 0, &PathError{"seek", file.name, Errno(e)}
+ if e != nil {
+ return 0, &PathError{"seek", file.name, e}
}
return r, nil
}
@@ -160,16 +160,16 @@ func (file *File) WriteString(s string) (ret int, err error) {
// It returns an error, if any.
func Mkdir(name string, perm uint32) error {
e := syscall.Mkdir(name, perm)
- if iserror(e) {
- return &PathError{"mkdir", name, Errno(e)}
+ if e != nil {
+ return &PathError{"mkdir", name, e}
}
return nil
}
// Chdir changes the current working directory to the named directory.
func Chdir(dir string) error {
- if e := syscall.Chdir(dir); iserror(e) {
- return &PathError{"chdir", dir, Errno(e)}
+ if e := syscall.Chdir(dir); e != nil {
+ return &PathError{"chdir", dir, e}
}
return nil
}
@@ -177,8 +177,8 @@ func Chdir(dir string) error {
// Chdir changes the current working directory to the file,
// which must be a directory.
func (f *File) Chdir() error {
- if e := syscall.Fchdir(f.fd); iserror(e) {
- return &PathError{"chdir", f.name, Errno(e)}
+ if e := syscall.Fchdir(f.fd); e != nil {
+ return &PathError{"chdir", f.name, e}
}
return nil
}
diff --git a/libgo/go/os/file_plan9.go b/libgo/go/os/file_plan9.go
index 42332e157ef..42fefa96fe8 100644
--- a/libgo/go/os/file_plan9.go
+++ b/libgo/go/os/file_plan9.go
@@ -11,6 +11,14 @@ import (
// File represents an open file descriptor.
type File struct {
+ *file
+}
+
+// file is the real representation of *File.
+// The extra level of indirection ensures that no clients of os
+// can overwrite this data, which could cause the finalizer
+// to close the wrong file descriptor.
+type file struct {
fd int
name string
dirinfo *dirInfo // nil unless directory being read
@@ -29,8 +37,8 @@ func NewFile(fd int, name string) *File {
if fd < 0 {
return nil
}
- f := &File{fd: fd, name: name}
- runtime.SetFinalizer(f, (*File).Close)
+ f := &File{&file{fd: fd, name: name}}
+ runtime.SetFinalizer(f.file, (*file).close)
return f
}
@@ -41,7 +49,7 @@ type dirInfo struct {
bufp int // location of next record in buf.
}
-func epipecheck(file *File, e syscall.Error) {
+func epipecheck(file *File, e error) {
}
// DevNull is the name of the operating system's ``null device.''
@@ -56,7 +64,7 @@ const DevNull = "/dev/null"
func OpenFile(name string, flag int, perm uint32) (file *File, err error) {
var (
fd int
- e syscall.Error
+ e error
create bool
excl bool
trunc bool
@@ -85,7 +93,7 @@ func OpenFile(name string, flag int, perm uint32) (file *File, err error) {
} else {
fd, e = syscall.Open(name, flag)
if e != nil && create {
- var e1 syscall.Error
+ var e1 error
fd, e1 = syscall.Create(name, flag, perm)
if e1 == nil {
e = nil
@@ -110,6 +118,10 @@ func OpenFile(name string, flag int, perm uint32) (file *File, err error) {
// Close closes the File, rendering it unusable for I/O.
// It returns an error, if any.
func (file *File) Close() error {
+ return file.file.close()
+}
+
+func (file *file) close() error {
if file == nil || file.fd < 0 {
return Ebadfd
}
@@ -130,7 +142,7 @@ func (file *File) Close() error {
// It returns the FileInfo and an error, if any.
func (f *File) Stat() (fi *FileInfo, err error) {
d, err := dirstat(f)
- if iserror(err) {
+ if err != nil {
return nil, err
}
return fileInfoFromStat(new(FileInfo), d), err
@@ -144,7 +156,7 @@ func (f *File) Truncate(size int64) error {
d.Length = uint64(size)
- if e := syscall.Fwstat(f.fd, pdir(nil, &d)); iserror(e) {
+ if e := syscall.Fwstat(f.fd, pdir(nil, &d)); e != nil {
return &PathError{"truncate", f.name, e}
}
return nil
@@ -157,12 +169,12 @@ func (f *File) Chmod(mode uint32) error {
d.Null()
odir, e := dirstat(f)
- if iserror(e) {
+ if e != nil {
return &PathError{"chmod", f.name, e}
}
d.Mode = (odir.Mode & mask) | (mode &^ mask)
- if e := syscall.Fwstat(f.fd, pdir(nil, &d)); iserror(e) {
+ if e := syscall.Fwstat(f.fd, pdir(nil, &d)); e != nil {
return &PathError{"chmod", f.name, e}
}
return nil
@@ -179,7 +191,7 @@ func (f *File) Sync() (err error) {
var d Dir
d.Null()
- if e := syscall.Fwstat(f.fd, pdir(nil, &d)); iserror(e) {
+ if e := syscall.Fwstat(f.fd, pdir(nil, &d)); e != nil {
return NewSyscallError("fsync", e)
}
return nil
@@ -187,26 +199,26 @@ func (f *File) Sync() (err error) {
// read reads up to len(b) bytes from the File.
// It returns the number of bytes read and an error, if any.
-func (f *File) read(b []byte) (n int, err syscall.Error) {
+func (f *File) read(b []byte) (n int, err error) {
return syscall.Read(f.fd, b)
}
// pread reads len(b) bytes from the File starting at byte offset off.
// It returns the number of bytes read and the error, if any.
// EOF is signaled by a zero count with err set to nil.
-func (f *File) pread(b []byte, off int64) (n int, err syscall.Error) {
+func (f *File) pread(b []byte, off int64) (n int, err error) {
return syscall.Pread(f.fd, b, off)
}
// write writes len(b) bytes to the File.
// It returns the number of bytes written and an error, if any.
-func (f *File) write(b []byte) (n int, err syscall.Error) {
+func (f *File) write(b []byte) (n int, err error) {
return syscall.Write(f.fd, b)
}
// pwrite writes len(b) bytes to the File starting at byte offset off.
// It returns the number of bytes written and an error, if any.
-func (f *File) pwrite(b []byte, off int64) (n int, err syscall.Error) {
+func (f *File) pwrite(b []byte, off int64) (n int, err error) {
return syscall.Pwrite(f.fd, b, off)
}
@@ -214,7 +226,7 @@ func (f *File) pwrite(b []byte, off int64) (n int, err syscall.Error) {
// according to whence: 0 means relative to the origin of the file, 1 means
// relative to the current offset, and 2 means relative to the end.
// It returns the new offset and an error, if any.
-func (f *File) seek(offset int64, whence int) (ret int64, err syscall.Error) {
+func (f *File) seek(offset int64, whence int) (ret int64, err error) {
return syscall.Seek(f.fd, offset, whence)
}
@@ -226,7 +238,7 @@ func Truncate(name string, size int64) error {
d.Length = uint64(size)
- if e := syscall.Wstat(name, pdir(nil, &d)); iserror(e) {
+ if e := syscall.Wstat(name, pdir(nil, &d)); e != nil {
return &PathError{"truncate", name, e}
}
return nil
@@ -234,7 +246,7 @@ func Truncate(name string, size int64) error {
// Remove removes the named file or directory.
func Remove(name string) error {
- if e := syscall.Remove(name); iserror(e) {
+ if e := syscall.Remove(name); e != nil {
return &PathError{"remove", name, e}
}
return nil
@@ -247,7 +259,7 @@ func Rename(oldname, newname string) error {
d.Name = newname
- if e := syscall.Wstat(oldname, pdir(nil, &d)); iserror(e) {
+ if e := syscall.Wstat(oldname, pdir(nil, &d)); e != nil {
return &PathError{"rename", oldname, e}
}
return nil
@@ -260,12 +272,12 @@ func Chmod(name string, mode uint32) error {
d.Null()
odir, e := dirstat(name)
- if iserror(e) {
+ if e != nil {
return &PathError{"chmod", name, e}
}
d.Mode = (odir.Mode & mask) | (mode &^ mask)
- if e := syscall.Wstat(name, pdir(nil, &d)); iserror(e) {
+ if e := syscall.Wstat(name, pdir(nil, &d)); e != nil {
return &PathError{"chmod", name, e}
}
return nil
@@ -284,7 +296,7 @@ func Chtimes(name string, atimeNs int64, mtimeNs int64) error {
d.Atime = uint32(atimeNs / 1e9)
d.Mtime = uint32(mtimeNs / 1e9)
- if e := syscall.Wstat(name, pdir(nil, &d)); iserror(e) {
+ if e := syscall.Wstat(name, pdir(nil, &d)); e != nil {
return &PathError{"chtimes", name, e}
}
return nil
@@ -294,7 +306,7 @@ func Pipe() (r *File, w *File, err error) {
var p [2]int
syscall.ForkLock.RLock()
- if e := syscall.Pipe(p[0:]); iserror(e) {
+ if e := syscall.Pipe(p[0:]); e != nil {
syscall.ForkLock.RUnlock()
return nil, nil, NewSyscallError("pipe", e)
}
@@ -329,3 +341,8 @@ func Lchown(name string, uid, gid int) error {
func (f *File) Chown(uid, gid int) error {
return EPLAN9
}
+
+// TempDir returns the default directory to use for temporary files.
+func TempDir() string {
+ return "/tmp"
+}
diff --git a/libgo/go/os/file_posix.go b/libgo/go/os/file_posix.go
index c937b6d6266..c80d3df5e50 100644
--- a/libgo/go/os/file_posix.go
+++ b/libgo/go/os/file_posix.go
@@ -12,7 +12,7 @@ import (
func sigpipe() // implemented in package runtime
-func epipecheck(file *File, e int) {
+func epipecheck(file *File, e error) {
if e == syscall.EPIPE {
file.nepipe++
if file.nepipe >= 10 {
@@ -30,11 +30,11 @@ func Remove(name string) error {
// Try both: it is cheaper on average than
// doing a Stat plus the right one.
e := syscall.Unlink(name)
- if !iserror(e) {
+ if e == nil {
return nil
}
e1 := syscall.Rmdir(name)
- if !iserror(e1) {
+ if e1 == nil {
return nil
}
@@ -53,7 +53,7 @@ func Remove(name string) error {
if e1 != syscall.ENOTDIR {
e = e1
}
- return &PathError{"remove", name, Errno(e)}
+ return &PathError{"remove", name, e}
}
// LinkError records an error during a link or symlink or rename
@@ -72,8 +72,8 @@ func (e *LinkError) Error() string {
// Link creates a hard link.
func Link(oldname, newname string) error {
e := syscall.Link(oldname, newname)
- if iserror(e) {
- return &LinkError{"link", oldname, newname, Errno(e)}
+ if e != nil {
+ return &LinkError{"link", oldname, newname, e}
}
return nil
}
@@ -81,8 +81,8 @@ func Link(oldname, newname string) error {
// Symlink creates a symbolic link.
func Symlink(oldname, newname string) error {
e := syscall.Symlink(oldname, newname)
- if iserror(e) {
- return &LinkError{"symlink", oldname, newname, Errno(e)}
+ if e != nil {
+ return &LinkError{"symlink", oldname, newname, e}
}
return nil
}
@@ -93,8 +93,8 @@ func Readlink(name string) (string, error) {
for len := 128; ; len *= 2 {
b := make([]byte, len)
n, e := syscall.Readlink(name, b)
- if iserror(e) {
- return "", &PathError{"readlink", name, Errno(e)}
+ if e != nil {
+ return "", &PathError{"readlink", name, e}
}
if n < len {
return string(b[0:n]), nil
@@ -107,8 +107,8 @@ func Readlink(name string) (string, error) {
// Rename renames a file.
func Rename(oldname, newname string) error {
e := syscall.Rename(oldname, newname)
- if iserror(e) {
- return &LinkError{"rename", oldname, newname, Errno(e)}
+ if e != nil {
+ return &LinkError{"rename", oldname, newname, e}
}
return nil
}
@@ -116,16 +116,16 @@ func Rename(oldname, newname string) error {
// Chmod changes the mode of the named file to mode.
// If the file is a symbolic link, it changes the mode of the link's target.
func Chmod(name string, mode uint32) error {
- if e := syscall.Chmod(name, mode); iserror(e) {
- return &PathError{"chmod", name, Errno(e)}
+ if e := syscall.Chmod(name, mode); e != nil {
+ return &PathError{"chmod", name, e}
}
return nil
}
// Chmod changes the mode of the file to mode.
func (f *File) Chmod(mode uint32) error {
- if e := syscall.Fchmod(f.fd, mode); iserror(e) {
- return &PathError{"chmod", f.name, Errno(e)}
+ if e := syscall.Fchmod(f.fd, mode); e != nil {
+ return &PathError{"chmod", f.name, e}
}
return nil
}
@@ -133,8 +133,8 @@ func (f *File) Chmod(mode uint32) error {
// Chown changes the numeric uid and gid of the named file.
// If the file is a symbolic link, it changes the uid and gid of the link's target.
func Chown(name string, uid, gid int) error {
- if e := syscall.Chown(name, uid, gid); iserror(e) {
- return &PathError{"chown", name, Errno(e)}
+ if e := syscall.Chown(name, uid, gid); e != nil {
+ return &PathError{"chown", name, e}
}
return nil
}
@@ -142,16 +142,16 @@ func Chown(name string, uid, gid int) error {
// Lchown changes the numeric uid and gid of the named file.
// If the file is a symbolic link, it changes the uid and gid of the link itself.
func Lchown(name string, uid, gid int) error {
- if e := syscall.Lchown(name, uid, gid); iserror(e) {
- return &PathError{"lchown", name, Errno(e)}
+ if e := syscall.Lchown(name, uid, gid); e != nil {
+ return &PathError{"lchown", name, e}
}
return nil
}
// Chown changes the numeric uid and gid of the named file.
func (f *File) Chown(uid, gid int) error {
- if e := syscall.Fchown(f.fd, uid, gid); iserror(e) {
- return &PathError{"chown", f.name, Errno(e)}
+ if e := syscall.Fchown(f.fd, uid, gid); e != nil {
+ return &PathError{"chown", f.name, e}
}
return nil
}
@@ -159,8 +159,8 @@ func (f *File) Chown(uid, gid int) error {
// Truncate changes the size of the file.
// It does not change the I/O offset.
func (f *File) Truncate(size int64) error {
- if e := syscall.Ftruncate(f.fd, size); iserror(e) {
- return &PathError{"truncate", f.name, Errno(e)}
+ if e := syscall.Ftruncate(f.fd, size); e != nil {
+ return &PathError{"truncate", f.name, e}
}
return nil
}
@@ -172,7 +172,7 @@ func (file *File) Sync() (err error) {
if file == nil {
return EINVAL
}
- if e := syscall.Fsync(file.fd); iserror(e) {
+ if e := syscall.Fsync(file.fd); e != nil {
return NewSyscallError("fsync", e)
}
return nil
@@ -188,8 +188,8 @@ func Chtimes(name string, atime_ns int64, mtime_ns int64) error {
var utimes [2]syscall.Timeval
utimes[0] = syscall.NsecToTimeval(atime_ns)
utimes[1] = syscall.NsecToTimeval(mtime_ns)
- if e := syscall.Utimes(name, utimes[0:]); iserror(e) {
- return &PathError{"chtimes", name, Errno(e)}
+ if e := syscall.Utimes(name, utimes[0:]); e != nil {
+ return &PathError{"chtimes", name, e}
}
return nil
}
diff --git a/libgo/go/os/file_unix.go b/libgo/go/os/file_unix.go
index a7ccb337eb5..0bf31ecb9a7 100644
--- a/libgo/go/os/file_unix.go
+++ b/libgo/go/os/file_unix.go
@@ -13,6 +13,14 @@ import (
// File represents an open file descriptor.
type File struct {
+ *file
+}
+
+// file is the real representation of *File.
+// The extra level of indirection ensures that no clients of os
+// can overwrite this data, which could cause the finalizer
+// to close the wrong file descriptor.
+type file struct {
fd int
name string
dirinfo *dirInfo // nil unless directory being read
@@ -32,8 +40,8 @@ func NewFile(fd int, name string) *File {
if fd < 0 {
return nil
}
- f := &File{fd: fd, name: name}
- runtime.SetFinalizer(f, (*File).Close)
+ f := &File{&file{fd: fd, name: name}}
+ runtime.SetFinalizer(f.file, (*file).close)
return f
}
@@ -54,8 +62,8 @@ const DevNull = "/dev/null"
// It returns the File and an error, if any.
func OpenFile(name string, flag int, perm uint32) (file *File, err error) {
r, e := syscall.Open(name, flag|syscall.O_CLOEXEC, perm)
- if e != 0 {
- return nil, &PathError{"open", name, Errno(e)}
+ if e != nil {
+ return nil, &PathError{"open", name, e}
}
// There's a race here with fork/exec, which we are
@@ -70,17 +78,21 @@ func OpenFile(name string, flag int, perm uint32) (file *File, err error) {
// Close closes the File, rendering it unusable for I/O.
// It returns an error, if any.
func (file *File) Close() error {
+ return file.file.close()
+}
+
+func (file *file) close() error {
if file == nil || file.fd < 0 {
return EINVAL
}
var err error
- if e := syscall.Close(file.fd); e != 0 {
- err = &PathError{"close", file.name, Errno(e)}
+ if e := syscall.Close(file.fd); e != nil {
+ err = &PathError{"close", file.name, e}
}
if file.dirinfo != nil {
if libc_closedir(file.dirinfo.dir) < 0 && err == nil {
- err = &PathError{"closedir", file.name, Errno(syscall.GetErrno())}
+ err = &PathError{"closedir", file.name, syscall.GetErrno()}
}
}
@@ -96,8 +108,8 @@ func (file *File) Close() error {
func (file *File) Stat() (fi *FileInfo, err error) {
var stat syscall.Stat_t
e := syscall.Fstat(file.fd, &stat)
- if e != 0 {
- return nil, &PathError{"stat", file.name, Errno(e)}
+ if e != nil {
+ return nil, &PathError{"stat", file.name, e}
}
return fileInfoFromStat(file.name, new(FileInfo), &stat, &stat), nil
}
@@ -110,13 +122,13 @@ func (file *File) Stat() (fi *FileInfo, err error) {
func Stat(name string) (fi *FileInfo, err error) {
var lstat, stat syscall.Stat_t
e := syscall.Lstat(name, &lstat)
- if iserror(e) {
- return nil, &PathError{"stat", name, Errno(e)}
+ if e != nil {
+ return nil, &PathError{"stat", name, e}
}
statp := &lstat
if lstat.Mode&syscall.S_IFMT == syscall.S_IFLNK {
e := syscall.Stat(name, &stat)
- if !iserror(e) {
+ if e == nil {
statp = &stat
}
}
@@ -129,8 +141,8 @@ func Stat(name string) (fi *FileInfo, err error) {
func Lstat(name string) (fi *FileInfo, err error) {
var stat syscall.Stat_t
e := syscall.Lstat(name, &stat)
- if iserror(e) {
- return nil, &PathError{"lstat", name, Errno(e)}
+ if e != nil {
+ return nil, &PathError{"lstat", name, e}
}
return fileInfoFromStat(name, new(FileInfo), &stat, &stat), nil
}
@@ -171,26 +183,26 @@ func (file *File) Readdir(n int) (fi []FileInfo, err error) {
// read reads up to len(b) bytes from the File.
// It returns the number of bytes read and an error, if any.
-func (f *File) read(b []byte) (n int, err int) {
+func (f *File) read(b []byte) (n int, err error) {
return syscall.Read(f.fd, b)
}
// pread reads len(b) bytes from the File starting at byte offset off.
// It returns the number of bytes read and the error, if any.
// EOF is signaled by a zero count with err set to 0.
-func (f *File) pread(b []byte, off int64) (n int, err int) {
+func (f *File) pread(b []byte, off int64) (n int, err error) {
return syscall.Pread(f.fd, b, off)
}
// write writes len(b) bytes to the File.
// It returns the number of bytes written and an error, if any.
-func (f *File) write(b []byte) (n int, err int) {
+func (f *File) write(b []byte) (n int, err error) {
return syscall.Write(f.fd, b)
}
// pwrite writes len(b) bytes to the File starting at byte offset off.
// It returns the number of bytes written and an error, if any.
-func (f *File) pwrite(b []byte, off int64) (n int, err int) {
+func (f *File) pwrite(b []byte, off int64) (n int, err error) {
return syscall.Pwrite(f.fd, b, off)
}
@@ -198,15 +210,15 @@ func (f *File) pwrite(b []byte, off int64) (n int, err int) {
// according to whence: 0 means relative to the origin of the file, 1 means
// relative to the current offset, and 2 means relative to the end.
// It returns the new offset and an error, if any.
-func (f *File) seek(offset int64, whence int) (ret int64, err int) {
+func (f *File) seek(offset int64, whence int) (ret int64, err error) {
return syscall.Seek(f.fd, offset, whence)
}
// Truncate changes the size of the named file.
// If the file is a symbolic link, it changes the size of the link's target.
func Truncate(name string, size int64) error {
- if e := syscall.Truncate(name, size); e != 0 {
- return &PathError{"truncate", name, Errno(e)}
+ if e := syscall.Truncate(name, size); e != nil {
+ return &PathError{"truncate", name, e}
}
return nil
}
@@ -237,7 +249,7 @@ func Pipe() (r *File, w *File, err error) {
// See ../syscall/exec.go for description of lock.
syscall.ForkLock.RLock()
e := syscall.Pipe(p[0:])
- if iserror(e) {
+ if e != nil {
syscall.ForkLock.RUnlock()
return nil, nil, NewSyscallError("pipe", e)
}
@@ -247,3 +259,12 @@ func Pipe() (r *File, w *File, err error) {
return NewFile(p[0], "|0"), NewFile(p[1], "|1"), nil
}
+
+// TempDir returns the default directory to use for temporary files.
+func TempDir() string {
+ dir := Getenv("TMPDIR")
+ if dir == "" {
+ dir = "/tmp"
+ }
+ return dir
+}
diff --git a/libgo/go/os/os_test.go b/libgo/go/os/os_test.go
index 1d6d872d5c7..170f7331c6e 100644
--- a/libgo/go/os/os_test.go
+++ b/libgo/go/os/os_test.go
@@ -18,7 +18,7 @@ import (
var dot = []string{
"dir_unix.go",
- "env_unix.go",
+ "env.go",
"error.go",
"file.go",
"os_test.go",
@@ -940,11 +940,6 @@ func TestHostname(t *testing.T) {
return
}
- // TODO(jsing): Fix nametomib() on OpenBSD
- if syscall.OS == "openbsd" {
- return
- }
-
// Check internal Hostname() against the output of /bin/hostname.
// Allow that the internal Hostname returns a Fully Qualified Domain Name
// and the /bin/hostname only returns the first component
diff --git a/libgo/go/os/proc.go b/libgo/go/os/proc.go
index d21f849f210..61545f4456a 100644
--- a/libgo/go/os/proc.go
+++ b/libgo/go/os/proc.go
@@ -8,8 +8,8 @@ package os
import "syscall"
-var Args []string // provided by runtime
-var Envs []string // provided by runtime
+// Args hold the command-line arguments, starting with the program name.
+var Args []string
// Getuid returns the numeric user id of the caller.
func Getuid() int { return syscall.Getuid() }
diff --git a/libgo/go/os/stat_plan9.go b/libgo/go/os/stat_plan9.go
index 8df9e580cc4..e4a1dbbaea3 100644
--- a/libgo/go/os/stat_plan9.go
+++ b/libgo/go/os/stat_plan9.go
@@ -34,7 +34,7 @@ func dirstat(arg interface{}) (d *Dir, err error) {
buf := make([]byte, nd)
var n int
- var e syscall.Error
+ var e error
switch syscallArg := arg.(type) {
case *File:
@@ -72,7 +72,7 @@ func dirstat(arg interface{}) (d *Dir, err error) {
// Stat returns a FileInfo structure describing the named file and an error, if any.
func Stat(name string) (fi *FileInfo, err error) {
d, err := dirstat(name)
- if iserror(err) {
+ if err != nil {
return nil, err
}
return fileInfoFromStat(new(FileInfo), d), err
@@ -83,7 +83,7 @@ func Stat(name string) (fi *FileInfo, err error) {
// the returned FileInfo describes the symbolic link. Lstat makes no attempt to follow the link.
func Lstat(name string) (fi *FileInfo, err error) {
d, err := dirstat(name)
- if iserror(err) {
+ if err != nil {
return nil, err
}
return fileInfoFromStat(new(FileInfo), d), err
diff --git a/libgo/go/os/sys_bsd.go b/libgo/go/os/sys_bsd.go
index 67133a1898b..c6a6de5c816 100644
--- a/libgo/go/os/sys_bsd.go
+++ b/libgo/go/os/sys_bsd.go
@@ -12,10 +12,9 @@ package os
import "syscall"
func Hostname() (name string, err error) {
- var errno int
- name, errno = syscall.Sysctl("kern.hostname")
- if errno != 0 {
- return "", NewSyscallError("sysctl kern.hostname", errno)
+ name, err = syscall.Sysctl("kern.hostname")
+ if err != nil {
+ return "", NewSyscallError("sysctl kern.hostname", err)
}
return name, nil
}
diff --git a/libgo/go/os/time.go b/libgo/go/os/time.go
index a4678ee2a16..eb564e57a6c 100644
--- a/libgo/go/os/time.go
+++ b/libgo/go/os/time.go
@@ -12,7 +12,7 @@ import "syscall"
// time is the Unix epoch.
func Time() (sec int64, nsec int64, err error) {
var tv syscall.Timeval
- if e := syscall.Gettimeofday(&tv); iserror(e) {
+ if e := syscall.Gettimeofday(&tv); e != nil {
return 0, 0, NewSyscallError("gettimeofday", e)
}
return int64(tv.Sec), int64(tv.Usec) * 1000, err
diff --git a/libgo/go/os/user/lookup_unix.go b/libgo/go/os/user/lookup_unix.go
index ba4e1ac7991..89886cb03cf 100644
--- a/libgo/go/os/user/lookup_unix.go
+++ b/libgo/go/os/user/lookup_unix.go
@@ -8,7 +8,6 @@ package user
import (
"fmt"
- "os"
"strings"
"syscall"
"unsafe"
@@ -70,7 +69,7 @@ func lookup(uid int, username string, lookupByName bool) (*User, error) {
bufSize,
&result)
if rv != 0 {
- return nil, fmt.Errorf("user: lookup username %s: %s", username, os.Errno(syscall.GetErrno()))
+ return nil, fmt.Errorf("user: lookup username %s: %s", username, syscall.GetErrno())
}
if result == nil {
return nil, UnknownUserError(username)
@@ -82,7 +81,7 @@ func lookup(uid int, username string, lookupByName bool) (*User, error) {
bufSize,
&result)
if rv != 0 {
- return nil, fmt.Errorf("user: lookup userid %d: %s", uid, os.Errno(syscall.GetErrno()))
+ return nil, fmt.Errorf("user: lookup userid %d: %s", uid, syscall.GetErrno())
}
if result == nil {
return nil, UnknownUserIdError(uid)
diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go
index 7c1022ecb48..cf31d1ba39d 100644
--- a/libgo/go/reflect/all_test.go
+++ b/libgo/go/reflect/all_test.go
@@ -16,6 +16,13 @@ import (
"unsafe"
)
+func TestBool(t *testing.T) {
+ v := ValueOf(true)
+ if v.Bool() != true {
+ t.Fatal("ValueOf(true).Bool() = false")
+ }
+}
+
type integer int
type T struct {
a int
@@ -215,7 +222,8 @@ func TestTypes(t *testing.T) {
func TestSet(t *testing.T) {
for i, tt := range valueTests {
- v := ValueOf(tt.i).Elem()
+ v := ValueOf(tt.i)
+ v = v.Elem()
switch v.Kind() {
case Int:
v.SetInt(132)
@@ -651,6 +659,14 @@ var deepEqualTests = []DeepEqualTest{
{nil, 1, false},
{1, nil, false},
+ // Nil vs empty: not the same.
+ {[]int{}, []int(nil), false},
+ {[]int{}, []int{}, true},
+ {[]int(nil), []int(nil), true},
+ {map[int]int{}, map[int]int(nil), false},
+ {map[int]int{}, map[int]int{}, true},
+ {map[int]int(nil), map[int]int(nil), true},
+
// Mismatched types
{1, 1.0, false},
{int32(1), int64(1), false},
@@ -1092,21 +1108,38 @@ func TestMethod(t *testing.T) {
}
// Curried method of value.
- i = ValueOf(p).Method(1).Call([]Value{ValueOf(10)})[0].Int()
+ tfunc := TypeOf(func(int) int(nil))
+ v := ValueOf(p).Method(1)
+ if tt := v.Type(); tt != tfunc {
+ t.Errorf("Value Method Type is %s; want %s", tt, tfunc)
+ }
+ i = v.Call([]Value{ValueOf(10)})[0].Int()
if i != 250 {
t.Errorf("Value Method returned %d; want 250", i)
}
- i = ValueOf(p).MethodByName("Dist").Call([]Value{ValueOf(10)})[0].Int()
+ v = ValueOf(p).MethodByName("Dist")
+ if tt := v.Type(); tt != tfunc {
+ t.Errorf("Value MethodByName Type is %s; want %s", tt, tfunc)
+ }
+ i = v.Call([]Value{ValueOf(10)})[0].Int()
if i != 250 {
t.Errorf("Value MethodByName returned %d; want 250", i)
}
// Curried method of pointer.
- i = ValueOf(&p).Method(1).Call([]Value{ValueOf(10)})[0].Int()
+ v = ValueOf(&p).Method(1)
+ if tt := v.Type(); tt != tfunc {
+ t.Errorf("Pointer Value Method Type is %s; want %s", tt, tfunc)
+ }
+ i = v.Call([]Value{ValueOf(10)})[0].Int()
if i != 250 {
t.Errorf("Pointer Value Method returned %d; want 250", i)
}
- i = ValueOf(&p).MethodByName("Dist").Call([]Value{ValueOf(10)})[0].Int()
+ v = ValueOf(&p).MethodByName("Dist")
+ if tt := v.Type(); tt != tfunc {
+ t.Errorf("Pointer Value MethodByName Type is %s; want %s", tt, tfunc)
+ }
+ i = v.Call([]Value{ValueOf(10)})[0].Int()
if i != 250 {
t.Errorf("Pointer Value MethodByName returned %d; want 250", i)
}
@@ -1121,11 +1154,19 @@ func TestMethod(t *testing.T) {
}
}{p}
pv := ValueOf(s).Field(0)
- i = pv.Method(0).Call([]Value{ValueOf(10)})[0].Int()
+ v = pv.Method(0)
+ if tt := v.Type(); tt != tfunc {
+ t.Errorf("Interface Method Type is %s; want %s", tt, tfunc)
+ }
+ i = v.Call([]Value{ValueOf(10)})[0].Int()
if i != 250 {
t.Errorf("Interface Method returned %d; want 250", i)
}
- i = pv.MethodByName("Dist").Call([]Value{ValueOf(10)})[0].Int()
+ v = pv.MethodByName("Dist")
+ if tt := v.Type(); tt != tfunc {
+ t.Errorf("Interface MethodByName Type is %s; want %s", tt, tfunc)
+ }
+ i = v.Call([]Value{ValueOf(10)})[0].Int()
if i != 250 {
t.Errorf("Interface MethodByName returned %d; want 250", i)
}
diff --git a/libgo/go/reflect/deepequal.go b/libgo/go/reflect/deepequal.go
index 63c28fe2024..df5ec0a6099 100644
--- a/libgo/go/reflect/deepequal.go
+++ b/libgo/go/reflect/deepequal.go
@@ -69,6 +69,9 @@ func deepValueEqual(v1, v2 Value, visited map[uintptr]*visit, depth int) (b bool
}
return true
case Slice:
+ if v1.IsNil() != v2.IsNil() {
+ return false
+ }
if v1.Len() != v2.Len() {
return false
}
@@ -93,6 +96,9 @@ func deepValueEqual(v1, v2 Value, visited map[uintptr]*visit, depth int) (b bool
}
return true
case Map:
+ if v1.IsNil() != v2.IsNil() {
+ return false
+ }
if v1.Len() != v2.Len() {
return false
}
diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go
index 9be7f830875..07cc0f5ba40 100644
--- a/libgo/go/reflect/type.go
+++ b/libgo/go/reflect/type.go
@@ -188,7 +188,7 @@ type Type interface {
// A Kind represents the specific kind of type that a Type represents.
// The zero Kind is not a valid kind.
-type Kind uint8
+type Kind uint
const (
Invalid Kind = iota
@@ -455,15 +455,16 @@ func (t *uncommonType) Method(i int) (m Method) {
if p.name != nil {
m.Name = *p.name
}
- flag := uint32(0)
+ fl := flag(Func) << flagKindShift
if p.pkgPath != nil {
m.PkgPath = *p.pkgPath
- flag |= flagRO
+ fl |= flagRO
}
- m.Type = toType(p.typ)
+ mt := toCommonType(p.typ)
+ m.Type = mt.toType()
x := new(unsafe.Pointer)
*x = p.tfn
- m.Func = valueFromIword(flag, m.Type, iword(uintptr(unsafe.Pointer(x))))
+ m.Func = Value{mt, unsafe.Pointer(x), fl|flagIndir}
m.Index = i
return
}
@@ -769,7 +770,7 @@ func (t *structType) Field(i int) (f StructField) {
if i < 0 || i >= len(t.fields) {
return
}
- p := t.fields[i]
+ p := &t.fields[i]
f.Type = toType(p.typ)
if p.name != nil {
f.Name = *p.name
@@ -868,10 +869,12 @@ L:
if n == 1 {
// Found matching field.
- if len(ff.Index) <= depth {
+ if depth >= len(ff.Index) {
ff.Index = make([]int, depth+1)
}
- ff.Index[depth] = fi
+ if len(ff.Index) > 1 {
+ ff.Index[depth] = fi
+ }
} else {
// None or more than one matching field found.
fd = inf
@@ -903,9 +906,6 @@ func toCommonType(p *runtime.Type) *commonType {
return nil
}
x := unsafe.Pointer(p)
- if uintptr(x)&reflectFlags != 0 {
- panic("reflect: invalid interface value")
- }
return (*commonType)(x)
}
@@ -967,10 +967,12 @@ func (t *commonType) runtimeType() *runtime.Type {
// PtrTo returns the pointer type with element t.
// For example, if t represents type Foo, PtrTo(t) represents *Foo.
func PtrTo(t Type) Type {
- // If t records its pointer-to type, use it.
- ct := t.(*commonType)
+ return t.(*commonType).ptrTo()
+}
+
+func (ct *commonType) ptrTo() *commonType {
if p := ct.ptrToThis; p != nil {
- return toType(p)
+ return toCommonType(p)
}
// Otherwise, synthesize one.
@@ -982,7 +984,7 @@ func PtrTo(t Type) Type {
if m := ptrMap.m; m != nil {
if p := m[ct]; p != nil {
ptrMap.RUnlock()
- return p.commonType.toType()
+ return &p.commonType
}
}
ptrMap.RUnlock()
@@ -994,7 +996,7 @@ func PtrTo(t Type) Type {
if p != nil {
// some other goroutine won the race and created it
ptrMap.Unlock()
- return p
+ return &p.commonType
}
rt := (*runtime.Type)(unsafe.Pointer(ct))
@@ -1024,7 +1026,7 @@ func PtrTo(t Type) Type {
ptrMap.m[ct] = p
ptrMap.Unlock()
- return p.commonType.toType()
+ return &p.commonType
}
func (t *commonType) Implements(u Type) bool {
diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go
index dbdfa09242f..b57ed462c84 100644
--- a/libgo/go/reflect/value.go
+++ b/libgo/go/reflect/value.go
@@ -11,6 +11,7 @@ import (
"unsafe"
)
+const bigEndian = false // can be smarter if we find a big-endian machine
const ptrSize = unsafe.Sizeof((*byte)(nil))
const cannotSet = "cannot set value obtained from unexported struct field"
@@ -53,14 +54,54 @@ func memmove(adst, asrc unsafe.Pointer, n uintptr) {
// its String method returns "<invalid Value>", and all other methods panic.
// Most functions and methods never return an invalid value.
// If one does, its documentation states the conditions explicitly.
-//
-// The fields of Value are exported so that clients can copy and
-// pass Values around, but they should not be edited or inspected
-// directly. A future language change may make it possible not to
-// export these fields while still keeping Values usable as values.
type Value struct {
- Internal interface{}
- InternalMethod int
+ // typ holds the type of the value represented by a Value.
+ typ *commonType
+
+ // val holds the 1-word representation of the value.
+ // If flag's flagIndir bit is set, then val is a pointer to the data.
+ // Otherwise val is a word holding the actual data.
+ // When the data is smaller than a word, it begins at
+ // the first byte (in the memory address sense) of val.
+ // We use unsafe.Pointer so that the garbage collector
+ // knows that val could be a pointer.
+ val unsafe.Pointer
+
+ // flag holds metadata about the value.
+ // The lowest bits are flag bits:
+ // - flagRO: obtained via unexported field, so read-only
+ // - flagIndir: val holds a pointer to the data
+ // - flagAddr: v.CanAddr is true (implies flagIndir)
+ // - flagMethod: v is a method value.
+ // The next five bits give the Kind of the value.
+ // This repeats typ.Kind() except for method values.
+ // The remaining 23+ bits give a method number for method values.
+ // If flag.kind() != Func, code can assume that flagMethod is unset.
+ // If typ.size > ptrSize, code can assume that flagIndir is set.
+ flag
+
+ // A method value represents a curried method invocation
+ // like r.Read for some receiver r. The typ+val+flag bits describe
+ // the receiver r, but the flag's Kind bits say Func (methods are
+ // functions), and the top bits of the flag give the method number
+ // in r's type's method table.
+}
+
+type flag uintptr
+
+const (
+ flagRO flag = 1 << iota
+ flagIndir
+ flagAddr
+ flagMethod
+ flagKindShift = iota
+ flagKindWidth = 5 // there are 27 kinds
+ flagKindMask flag = 1<<flagKindWidth - 1
+ flagMethodShift = flagKindShift + flagKindWidth
+)
+
+func (f flag) kind() Kind {
+ return Kind((f >> flagKindShift) & flagKindMask)
}
// A ValueError occurs when a Value method is invoked on
@@ -92,17 +133,30 @@ func methodName() string {
// An iword is the word that would be stored in an
// interface to represent a given value v. Specifically, if v is
// bigger than a pointer, its word is a pointer to v's data.
-// Otherwise, its word is a zero uintptr with the data stored
-// in the leading bytes.
-type iword uintptr
+// Otherwise, its word holds the data stored
+// in its leading bytes (so is not a pointer).
+// Because the value sometimes holds a pointer, we use
+// unsafe.Pointer to represent it, so that if iword appears
+// in a struct, the garbage collector knows that might be
+// a pointer.
+type iword unsafe.Pointer
+
+func (v Value) iword() iword {
+ if v.flag&flagIndir != 0 && (v.kind() == Ptr || v.kind() == UnsafePointer) {
+ // Have indirect but want direct word.
+ return loadIword(v.val, v.typ.size)
+ }
+ return iword(v.val)
+}
-func loadIword(p unsafe.Pointer, size uintptr) iword {
+// loadIword loads n bytes at p from memory into an iword.
+func loadIword(p unsafe.Pointer, n uintptr) iword {
// Run the copy ourselves instead of calling memmove
- // to avoid moving v to the heap.
- w := iword(0)
- switch size {
+ // to avoid moving w to the heap.
+ var w iword
+ switch n {
default:
- panic("reflect: internal error: loadIword of " + strconv.Itoa(int(size)) + "-byte value")
+ panic("reflect: internal error: loadIword of " + strconv.Itoa(int(n)) + "-byte value")
case 0:
case 1:
*(*uint8)(unsafe.Pointer(&w)) = *(*uint8)(p)
@@ -124,12 +178,13 @@ func loadIword(p unsafe.Pointer, size uintptr) iword {
return w
}
-func storeIword(p unsafe.Pointer, w iword, size uintptr) {
+// storeIword stores n bytes from w into p.
+func storeIword(p unsafe.Pointer, w iword, n uintptr) {
// Run the copy ourselves instead of calling memmove
- // to avoid moving v to the heap.
- switch size {
+ // to avoid moving w to the heap.
+ switch n {
default:
- panic("reflect: internal error: storeIword of " + strconv.Itoa(int(size)) + "-byte value")
+ panic("reflect: internal error: storeIword of " + strconv.Itoa(int(n)) + "-byte value")
case 0:
case 1:
*(*uint8)(p) = *(*uint8)(unsafe.Pointer(&w))
@@ -166,237 +221,42 @@ type nonEmptyInterface struct {
word iword
}
-// Regarding the implementation of Value:
-//
-// The Internal interface is a true interface value in the Go sense,
-// but it also serves as a (type, address) pair in which one cannot
-// be changed separately from the other. That is, it serves as a way
-// to prevent unsafe mutations of the Internal state even though
-// we cannot (yet?) hide the field while preserving the ability for
-// clients to make copies of Values.
-//
-// The internal method converts a Value into the expanded internalValue struct.
-// If we could avoid exporting fields we'd probably make internalValue the
-// definition of Value.
-//
-// If a Value is addressable (CanAddr returns true), then the Internal
-// interface value holds a pointer to the actual field data, and Set stores
-// through that pointer. If a Value is not addressable (CanAddr returns false),
-// then the Internal interface value holds the actual value.
-//
-// In addition to whether a value is addressable, we track whether it was
-// obtained by using an unexported struct field. Such values are allowed
-// to be read, mainly to make fmt.Print more useful, but they are not
-// allowed to be written. We call such values read-only.
-//
-// A Value can be set (via the Set, SetUint, etc. methods) only if it is both
-// addressable and not read-only.
-//
-// The two permission bits - addressable and read-only - are stored in
-// the bottom two bits of the type pointer in the interface value.
-//
-// ordinary value: Internal = value
-// addressable value: Internal = value, Internal.typ |= flagAddr
-// read-only value: Internal = value, Internal.typ |= flagRO
-// addressable, read-only value: Internal = value, Internal.typ |= flagAddr | flagRO
-//
-// It is important that the read-only values have the extra bit set
-// (as opposed to using the bit to mean writable), because client code
-// can grab the interface field and try to use it. Having the extra bit
-// set makes the type pointer compare not equal to any real type,
-// so that a client cannot, say, write through v.Internal.(*int).
-// The runtime routines that access interface types reject types with
-// low bits set.
-//
-// If a Value fv = v.Method(i), then fv = v with the InternalMethod
-// field set to i+1. Methods are never addressable.
-//
-// All in all, this is a lot of effort just to avoid making this new API
-// depend on a language change we'll probably do anyway, but
-// it's helpful to keep the two separate, and much of the logic is
-// necessary to implement the Interface method anyway.
-
-const (
- flagAddr uint32 = 1 << iota // holds address of value
- flagRO // read-only
-
- reflectFlags = 3
-)
-
-// An internalValue is the unpacked form of a Value.
-// The zero Value unpacks to a zero internalValue
-type internalValue struct {
- typ *commonType // type of value
- kind Kind // kind of value
- flag uint32
- word iword
- addr unsafe.Pointer
- rcvr iword
- method bool
- nilmethod bool
-}
-
-func (v Value) internal() internalValue {
- var iv internalValue
- eface := *(*emptyInterface)(unsafe.Pointer(&v.Internal))
- p := uintptr(unsafe.Pointer(eface.typ))
- iv.typ = toCommonType((*runtime.Type)(unsafe.Pointer(p &^ reflectFlags)))
- if iv.typ == nil {
- return iv
- }
- iv.flag = uint32(p & reflectFlags)
- iv.word = eface.word
- if iv.flag&flagAddr != 0 {
- iv.addr = unsafe.Pointer(uintptr(iv.word))
- iv.typ = iv.typ.Elem().common()
- if Kind(iv.typ.kind) == Ptr || Kind(iv.typ.kind) == UnsafePointer {
- iv.word = loadIword(iv.addr, iv.typ.size)
- }
- } else {
- if Kind(iv.typ.kind) != Ptr && Kind(iv.typ.kind) != UnsafePointer {
- iv.addr = unsafe.Pointer(uintptr(iv.word))
- }
+// mustBe panics if f's kind is not expected.
+// Making this a method on flag instead of on Value
+// (and embedding flag in Value) means that we can write
+// the very clear v.mustBe(Bool) and have it compile into
+// v.flag.mustBe(Bool), which will only bother to copy the
+// single important word for the receiver.
+func (f flag) mustBe(expected Kind) {
+ k := f.kind()
+ if k != expected {
+ panic(&ValueError{methodName(), k})
}
- iv.kind = iv.typ.Kind()
-
- // Is this a method? If so, iv describes the receiver.
- // Rewrite to describe the method function.
- if v.InternalMethod != 0 {
- // If this Value is a method value (x.Method(i) for some Value x)
- // then we will invoke it using the interface form of the method,
- // which always passes the receiver as a single word.
- // Record that information.
- i := v.InternalMethod - 1
- if iv.kind == Interface {
- it := (*interfaceType)(unsafe.Pointer(iv.typ))
- if i < 0 || i >= len(it.methods) {
- panic("reflect: broken Value")
- }
- m := &it.methods[i]
- if m.pkgPath != nil {
- iv.flag |= flagRO
- }
- iv.typ = toCommonType(m.typ)
- iface := (*nonEmptyInterface)(iv.addr)
- if iface.itab == nil {
- iv.word = 0
- iv.nilmethod = true
- } else {
- iv.word = iword(uintptr(iface.itab.fun[i]))
- }
- iv.rcvr = iface.word
- } else {
- ut := iv.typ.uncommon()
- if ut == nil || i < 0 || i >= len(ut.methods) {
- panic("reflect: broken Value")
- }
- m := &ut.methods[i]
- if m.pkgPath != nil {
- iv.flag |= flagRO
- }
- iv.typ = toCommonType(m.mtyp)
- iv.rcvr = iv.word
- iv.word = iword(uintptr(m.tfn))
- }
- if iv.word != 0 {
- p := new(iword)
- *p = iv.word
- iv.word = iword(uintptr(unsafe.Pointer(p)))
- }
- iv.kind = Func
- iv.method = true
- iv.flag &^= flagAddr
- iv.addr = unsafe.Pointer(uintptr(iv.word))
- }
-
- return iv
}
-// packValue returns a Value with the given flag bits, type, and interface word.
-func packValue(flag uint32, typ *runtime.Type, word iword) Value {
- if typ == nil {
- panic("packValue")
+// mustBeExported panics if f records that the value was obtained using
+// an unexported field.
+func (f flag) mustBeExported() {
+ if f == 0 {
+ panic(&ValueError{methodName(), 0})
}
- t := uintptr(unsafe.Pointer(typ))
- t |= uintptr(flag)
- eface := emptyInterface{(*runtime.Type)(unsafe.Pointer(t)), word}
- return Value{Internal: *(*interface{})(unsafe.Pointer(&eface))}
-}
-
-var dummy struct {
- b bool
- x interface{}
-}
-
-// Dummy annotation marking that the value x escapes,
-// for use in cases where the reflect code is so clever that
-// the compiler cannot follow.
-func escapes(x interface{}) {
- if dummy.b {
- dummy.x = x
- }
-}
-
-// valueFromAddr returns a Value using the given type and address.
-func valueFromAddr(flag uint32, typ Type, addr unsafe.Pointer) Value {
- // TODO(rsc): Eliminate this terrible hack.
- // The escape analysis knows that addr is a pointer
- // but it doesn't see addr get passed to anything
- // that keeps it. packValue keeps it, but packValue
- // takes a uintptr (iword(addr)), and integers (non-pointers)
- // are assumed not to matter. The escapes function works
- // because return values always escape (for now).
- escapes(addr)
-
- if flag&flagAddr != 0 {
- // Addressable, so the internal value is
- // an interface containing a pointer to the real value.
- return packValue(flag, PtrTo(typ).runtimeType(), iword(uintptr(addr)))
- }
-
- var w iword
- if k := typ.Kind(); k == Ptr || k == UnsafePointer {
- // In line, so the interface word is the actual value.
- w = loadIword(addr, typ.Size())
- } else {
- // Not in line: the interface word is the address.
- w = iword(uintptr(addr))
- }
- return packValue(flag, typ.runtimeType(), w)
-}
-
-// valueFromIword returns a Value using the given type and interface word.
-func valueFromIword(flag uint32, typ Type, w iword) Value {
- if flag&flagAddr != 0 {
- panic("reflect: internal error: valueFromIword addressable")
- }
- return packValue(flag, typ.runtimeType(), w)
-}
-
-func (iv internalValue) mustBe(want Kind) {
- if iv.kind != want {
- panic(&ValueError{methodName(), iv.kind})
- }
-}
-
-func (iv internalValue) mustBeExported() {
- if iv.kind == 0 {
- panic(&ValueError{methodName(), iv.kind})
- }
- if iv.flag&flagRO != 0 {
+ if f&flagRO != 0 {
panic(methodName() + " using value obtained using unexported field")
}
}
-func (iv internalValue) mustBeAssignable() {
- if iv.kind == 0 {
- panic(&ValueError{methodName(), iv.kind})
+// mustBeAssignable panics if f records that the value is not assignable,
+// which is to say that either it was obtained using an unexported field
+// or it is not addressable.
+func (f flag) mustBeAssignable() {
+ if f == 0 {
+ panic(&ValueError{methodName(), Invalid})
}
// Assignable if addressable and not read-only.
- if iv.flag&flagRO != 0 {
+ if f&flagRO != 0 {
panic(methodName() + " using value obtained using unexported field")
}
- if iv.flag&flagAddr == 0 {
+ if f&flagAddr == 0 {
panic(methodName() + " using unaddressable value")
}
}
@@ -407,31 +267,31 @@ func (iv internalValue) mustBeAssignable() {
// or slice element in order to call a method that requires a
// pointer receiver.
func (v Value) Addr() Value {
- iv := v.internal()
- if iv.flag&flagAddr == 0 {
+ if v.flag&flagAddr == 0 {
panic("reflect.Value.Addr of unaddressable value")
}
- return valueFromIword(iv.flag&flagRO, PtrTo(iv.typ.toType()), iword(uintptr(iv.addr)))
+ return Value{v.typ.ptrTo(), v.val, (v.flag & flagRO) | flag(Ptr)<<flagKindShift}
}
// Bool returns v's underlying value.
// It panics if v's kind is not Bool.
func (v Value) Bool() bool {
- iv := v.internal()
- iv.mustBe(Bool)
- return *(*bool)(unsafe.Pointer(iv.addr))
+ v.mustBe(Bool)
+ if v.flag&flagIndir != 0 {
+ return *(*bool)(v.val)
+ }
+ return *(*bool)(unsafe.Pointer(&v.val))
}
// Bytes returns v's underlying value.
// It panics if v's underlying value is not a slice of bytes.
func (v Value) Bytes() []byte {
- iv := v.internal()
- iv.mustBe(Slice)
- typ := iv.typ.toType()
- if typ.Elem().Kind() != Uint8 {
+ v.mustBe(Slice)
+ if v.typ.Elem().Kind() != Uint8 {
panic("reflect.Value.Bytes of non-byte slice")
}
- return *(*[]byte)(iv.addr)
+ // Slice is always bigger than a word; assume flagIndir.
+ return *(*[]byte)(v.val)
}
// CanAddr returns true if the value's address can be obtained with Addr.
@@ -440,8 +300,7 @@ func (v Value) Bytes() []byte {
// a field of an addressable struct, or the result of dereferencing a pointer.
// If CanAddr returns false, calling Addr will panic.
func (v Value) CanAddr() bool {
- iv := v.internal()
- return iv.flag&flagAddr != 0
+ return v.flag&flagAddr != 0
}
// CanSet returns true if the value of v can be changed.
@@ -450,8 +309,7 @@ func (v Value) CanAddr() bool {
// If CanSet returns false, calling Set or any type-specific
// setter (e.g., SetBool, SetInt64) will panic.
func (v Value) CanSet() bool {
- iv := v.internal()
- return iv.flag&(flagAddr|flagRO) == flagAddr
+ return v.flag&(flagAddr|flagRO) == flagAddr
}
// Call calls the function v with the input arguments in.
@@ -463,10 +321,9 @@ func (v Value) CanSet() bool {
// If v is a variadic function, Call creates the variadic slice parameter
// itself, copying in the corresponding values.
func (v Value) Call(in []Value) []Value {
- iv := v.internal()
- iv.mustBe(Func)
- iv.mustBeExported()
- return iv.call("Call", in)
+ v.mustBe(Func)
+ v.mustBeExported()
+ return v.call("Call", in)
}
// CallSlice calls the variadic function v with the input arguments in,
@@ -477,22 +334,60 @@ func (v Value) Call(in []Value) []Value {
// As in Go, each input argument must be assignable to the
// type of the function's corresponding input parameter.
func (v Value) CallSlice(in []Value) []Value {
- iv := v.internal()
- iv.mustBe(Func)
- iv.mustBeExported()
- return iv.call("CallSlice", in)
-}
-
-func (iv internalValue) call(method string, in []Value) []Value {
- if iv.word == 0 {
- if iv.nilmethod {
- panic("reflect.Value.Call: call of method on nil interface value")
+ v.mustBe(Func)
+ v.mustBeExported()
+ return v.call("CallSlice", in)
+}
+
+func (v Value) call(method string, in []Value) []Value {
+ // Get function pointer, type.
+ t := v.typ
+ var (
+ fn unsafe.Pointer
+ rcvr iword
+ )
+ if v.flag&flagMethod != 0 {
+ i := int(v.flag) >> flagMethodShift
+ if v.typ.Kind() == Interface {
+ tt := (*interfaceType)(unsafe.Pointer(v.typ))
+ if i < 0 || i >= len(tt.methods) {
+ panic("reflect: broken Value")
+ }
+ m := &tt.methods[i]
+ if m.pkgPath != nil {
+ panic(method + " of unexported method")
+ }
+ t = toCommonType(m.typ)
+ iface := (*nonEmptyInterface)(v.val)
+ if iface.itab == nil {
+ panic(method + " of method on nil interface value")
+ }
+ fn = iface.itab.fun[i]
+ rcvr = iface.word
+ } else {
+ ut := v.typ.uncommon()
+ if ut == nil || i < 0 || i >= len(ut.methods) {
+ panic("reflect: broken Value")
+ }
+ m := &ut.methods[i]
+ if m.pkgPath != nil {
+ panic(method + " of unexported method")
+ }
+ fn = m.tfn
+ t = toCommonType(m.mtyp)
+ rcvr = v.iword()
}
+ } else if v.flag&flagIndir != 0 {
+ fn = *(*unsafe.Pointer)(v.val)
+ } else {
+ fn = v.val
+ }
+
+ if fn == nil {
panic("reflect.Value.Call: call of nil function")
}
isSlice := method == "CallSlice"
- t := iv.typ
n := t.NumIn()
if isSlice {
if !t.IsVariadic() {
@@ -549,34 +444,32 @@ func (iv internalValue) call(method string, in []Value) []Value {
}
nout := t.NumOut()
- if iv.method {
+ if v.flag&flagMethod != 0 {
nin++
}
params := make([]unsafe.Pointer, nin)
delta := 0
off := 0
- if iv.method {
+ if v.flag&flagMethod != 0 {
// Hard-wired first argument.
p := new(iword)
- *p = iv.rcvr
+ *p = rcvr
params[0] = unsafe.Pointer(p)
off = 1
}
-
first_pointer := false
- for i, v := range in {
- siv := v.internal()
- siv.mustBeExported()
+ for i, pv := range in {
+ pv.mustBeExported()
targ := t.In(i).(*commonType)
- siv = convertForAssignment("reflect.Value.Call", nil, targ, siv)
- if siv.addr == nil {
+ pv = pv.assignTo("reflect.Value.Call", targ, nil)
+ if pv.flag&flagIndir == 0 {
p := new(unsafe.Pointer)
- *p = unsafe.Pointer(uintptr(siv.word))
+ *p = pv.val
params[off] = unsafe.Pointer(p)
} else {
- params[off] = siv.addr
+ params[off] = pv.val
}
- if i == 0 && Kind(targ.kind) != Ptr && !iv.method && isMethod(iv.typ) {
+ if i == 0 && Kind(targ.kind) != Ptr && v.flag&flagMethod == 0 && isMethod(v.typ) {
p := new(unsafe.Pointer)
*p = params[off]
params[off] = unsafe.Pointer(p)
@@ -602,7 +495,7 @@ func (iv internalValue) call(method string, in []Value) []Value {
pr = &results[0]
}
- call(t, *(*unsafe.Pointer)(iv.addr), iv.method, first_pointer, pp, pr)
+ call(t, fn, v.flag&flagMethod != 0, first_pointer, pp, pr)
return ret
}
@@ -635,39 +528,42 @@ func isMethod(t *commonType) bool {
// Cap returns v's capacity.
// It panics if v's Kind is not Array, Chan, or Slice.
func (v Value) Cap() int {
- iv := v.internal()
- switch iv.kind {
+ k := v.kind()
+ switch k {
case Array:
- return iv.typ.Len()
+ return v.typ.Len()
case Chan:
- return int(chancap(*(*iword)(iv.addr)))
+ return int(chancap(*(*iword)(v.iword())))
case Slice:
- return (*SliceHeader)(iv.addr).Cap
+ // Slice is always bigger than a word; assume flagIndir.
+ return (*SliceHeader)(v.val).Cap
}
- panic(&ValueError{"reflect.Value.Cap", iv.kind})
+ panic(&ValueError{"reflect.Value.Cap", k})
}
// Close closes the channel v.
// It panics if v's Kind is not Chan.
func (v Value) Close() {
- iv := v.internal()
- iv.mustBe(Chan)
- iv.mustBeExported()
- ch := *(*iword)(iv.addr)
- chanclose(ch)
+ v.mustBe(Chan)
+ v.mustBeExported()
+ chanclose(*(*iword)(v.iword()))
}
// Complex returns v's underlying value, as a complex128.
// It panics if v's Kind is not Complex64 or Complex128
func (v Value) Complex() complex128 {
- iv := v.internal()
- switch iv.kind {
+ k := v.kind()
+ switch k {
case Complex64:
- return complex128(*(*complex64)(iv.addr))
+ if v.flag&flagIndir != 0 {
+ return complex128(*(*complex64)(v.val))
+ }
+ return complex128(*(*complex64)(unsafe.Pointer(&v.val)))
case Complex128:
- return *(*complex128)(iv.addr)
+ // complex128 is always bigger than a word; assume flagIndir.
+ return *(*complex128)(v.val)
}
- panic(&ValueError{"reflect.Value.Complex", iv.kind})
+ panic(&ValueError{"reflect.Value.Complex", k})
}
// Elem returns the value that the interface v contains
@@ -675,90 +571,94 @@ func (v Value) Complex() complex128 {
// It panics if v's Kind is not Interface or Ptr.
// It returns the zero Value if v is nil.
func (v Value) Elem() Value {
- iv := v.internal()
- return iv.Elem()
-}
-
-func (iv internalValue) Elem() Value {
- switch iv.kind {
+ k := v.kind()
+ switch k {
case Interface:
- // Empty interface and non-empty interface have different layouts.
- // Convert to empty interface.
- var eface emptyInterface
- if iv.typ.NumMethod() == 0 {
- eface = *(*emptyInterface)(iv.addr)
+ var (
+ typ *commonType
+ val unsafe.Pointer
+ )
+ if v.typ.NumMethod() == 0 {
+ eface := (*emptyInterface)(v.val)
+ if eface.typ == nil {
+ // nil interface value
+ return Value{}
+ }
+ typ = toCommonType(eface.typ)
+ val = unsafe.Pointer(eface.word)
} else {
- iface := (*nonEmptyInterface)(iv.addr)
- if iface.itab != nil {
- eface.typ = iface.itab.typ
+ iface := (*nonEmptyInterface)(v.val)
+ if iface.itab == nil {
+ // nil interface value
+ return Value{}
}
- eface.word = iface.word
+ typ = toCommonType(iface.itab.typ)
+ val = unsafe.Pointer(iface.word)
}
- if eface.typ == nil {
- return Value{}
+ fl := v.flag & flagRO
+ fl |= flag(typ.Kind()) << flagKindShift
+ if typ.Kind() != Ptr && typ.Kind() != UnsafePointer {
+ fl |= flagIndir
}
- return valueFromIword(iv.flag&flagRO, toType(eface.typ), eface.word)
+ return Value{typ, val, fl}
case Ptr:
+ val := v.val
+ if v.flag&flagIndir != 0 {
+ val = *(*unsafe.Pointer)(val)
+ }
// The returned value's address is v's value.
- if iv.word == 0 {
+ if val == nil {
return Value{}
}
- return valueFromAddr(iv.flag&flagRO|flagAddr, iv.typ.Elem(), unsafe.Pointer(uintptr(iv.word)))
+ tt := (*ptrType)(unsafe.Pointer(v.typ))
+ typ := toCommonType(tt.elem)
+ fl := v.flag&flagRO | flagIndir | flagAddr
+ fl |= flag(typ.Kind() << flagKindShift)
+ return Value{typ, val, fl}
}
- panic(&ValueError{"reflect.Value.Elem", iv.kind})
+ panic(&ValueError{"reflect.Value.Elem", k})
}
// Field returns the i'th field of the struct v.
// It panics if v's Kind is not Struct or i is out of range.
func (v Value) Field(i int) Value {
- iv := v.internal()
- iv.mustBe(Struct)
- t := iv.typ.toType()
- if i < 0 || i >= t.NumField() {
+ v.mustBe(Struct)
+ tt := (*structType)(unsafe.Pointer(v.typ))
+ if i < 0 || i >= len(tt.fields) {
panic("reflect: Field index out of range")
}
- f := t.Field(i)
+ field := &tt.fields[i]
+ typ := toCommonType(field.typ)
// Inherit permission bits from v.
- flag := iv.flag
+ fl := v.flag & (flagRO | flagIndir | flagAddr)
// Using an unexported field forces flagRO.
- if f.PkgPath != "" {
- flag |= flagRO
+ if field.pkgPath != nil {
+ fl |= flagRO
}
- return valueFromValueOffset(flag, f.Type, iv, f.Offset)
-}
+ fl |= flag(typ.Kind()) << flagKindShift
-// valueFromValueOffset returns a sub-value of outer
-// (outer is an array or a struct) with the given flag and type
-// starting at the given byte offset into outer.
-func valueFromValueOffset(flag uint32, typ Type, outer internalValue, offset uintptr) Value {
- if outer.addr != nil {
- return valueFromAddr(flag, typ, unsafe.Pointer(uintptr(outer.addr)+offset))
+ var val unsafe.Pointer
+ switch {
+ case fl&flagIndir != 0:
+ // Indirect. Just bump pointer.
+ val = unsafe.Pointer(uintptr(v.val) + field.offset)
+ case bigEndian:
+ // Direct. Discard leading bytes.
+ val = unsafe.Pointer(uintptr(v.val) << (field.offset * 8))
+ default:
+ // Direct. Discard leading bytes.
+ val = unsafe.Pointer(uintptr(v.val) >> (field.offset * 8))
}
- // outer is so tiny it is in line.
- // We have to use outer.word and derive
- // the new word (it cannot possibly be bigger).
- // In line, so not addressable.
- if flag&flagAddr != 0 {
- panic("reflect: internal error: misuse of valueFromValueOffset")
- }
- b := *(*[ptrSize]byte)(unsafe.Pointer(&outer.word))
- for i := uintptr(0); i < typ.Size(); i++ {
- b[i] = b[offset+i]
- }
- for i := typ.Size(); i < ptrSize; i++ {
- b[i] = 0
- }
- w := *(*iword)(unsafe.Pointer(&b))
- return valueFromIword(flag, typ, w)
+ return Value{typ, val, fl}
}
// FieldByIndex returns the nested field corresponding to index.
// It panics if v's Kind is not struct.
func (v Value) FieldByIndex(index []int) Value {
- v.internal().mustBe(Struct)
+ v.mustBe(Struct)
for i, x := range index {
if i > 0 {
if v.Kind() == Ptr && v.Elem().Kind() == Struct {
@@ -774,9 +674,8 @@ func (v Value) FieldByIndex(index []int) Value {
// It returns the zero Value if no field was found.
// It panics if v's Kind is not struct.
func (v Value) FieldByName(name string) Value {
- iv := v.internal()
- iv.mustBe(Struct)
- if f, ok := iv.typ.FieldByName(name); ok {
+ v.mustBe(Struct)
+ if f, ok := v.typ.FieldByName(name); ok {
return v.FieldByIndex(f.Index)
}
return Value{}
@@ -787,8 +686,8 @@ func (v Value) FieldByName(name string) Value {
// It panics if v's Kind is not struct.
// It returns the zero Value if no field was found.
func (v Value) FieldByNameFunc(match func(string) bool) Value {
- v.internal().mustBe(Struct)
- if f, ok := v.Type().FieldByNameFunc(match); ok {
+ v.mustBe(Struct)
+ if f, ok := v.typ.FieldByNameFunc(match); ok {
return v.FieldByIndex(f.Index)
}
return Value{}
@@ -797,74 +696,101 @@ func (v Value) FieldByNameFunc(match func(string) bool) Value {
// Float returns v's underlying value, as an float64.
// It panics if v's Kind is not Float32 or Float64
func (v Value) Float() float64 {
- iv := v.internal()
- switch iv.kind {
+ k := v.kind()
+ switch k {
case Float32:
- return float64(*(*float32)(iv.addr))
+ if v.flag&flagIndir != 0 {
+ return float64(*(*float32)(v.val))
+ }
+ return float64(*(*float32)(unsafe.Pointer(&v.val)))
case Float64:
- return *(*float64)(iv.addr)
+ if v.flag&flagIndir != 0 {
+ return *(*float64)(v.val)
+ }
+ return *(*float64)(unsafe.Pointer(&v.val))
}
- panic(&ValueError{"reflect.Value.Float", iv.kind})
+ panic(&ValueError{"reflect.Value.Float", k})
}
// Index returns v's i'th element.
// It panics if v's Kind is not Array or Slice or i is out of range.
func (v Value) Index(i int) Value {
- iv := v.internal()
- switch iv.kind {
- default:
- panic(&ValueError{"reflect.Value.Index", iv.kind})
+ k := v.kind()
+ switch k {
case Array:
- flag := iv.flag // element flag same as overall array
- t := iv.typ.toType()
- if i < 0 || i > t.Len() {
+ tt := (*arrayType)(unsafe.Pointer(v.typ))
+ if i < 0 || i > int(tt.len) {
panic("reflect: array index out of range")
}
- typ := t.Elem()
- return valueFromValueOffset(flag, typ, iv, uintptr(i)*typ.Size())
+ typ := toCommonType(tt.elem)
+ fl := v.flag & (flagRO | flagIndir | flagAddr) // bits same as overall array
+ fl |= flag(typ.Kind()) << flagKindShift
+ offset := uintptr(i) * typ.size
+
+ var val unsafe.Pointer
+ switch {
+ case fl&flagIndir != 0:
+ // Indirect. Just bump pointer.
+ val = unsafe.Pointer(uintptr(v.val) + offset)
+ case bigEndian:
+ // Direct. Discard leading bytes.
+ val = unsafe.Pointer(uintptr(v.val) << (offset * 8))
+ default:
+ // Direct. Discard leading bytes.
+ val = unsafe.Pointer(uintptr(v.val) >> (offset * 8))
+ }
+ return Value{typ, val, fl}
case Slice:
// Element flag same as Elem of Ptr.
- // Addressable, possibly read-only.
- flag := iv.flag&flagRO | flagAddr
- s := (*SliceHeader)(iv.addr)
+ // Addressable, indirect, possibly read-only.
+ fl := flagAddr | flagIndir | v.flag&flagRO
+ s := (*SliceHeader)(v.val)
if i < 0 || i >= s.Len {
panic("reflect: slice index out of range")
}
- typ := iv.typ.Elem()
- addr := unsafe.Pointer(s.Data + uintptr(i)*typ.Size())
- return valueFromAddr(flag, typ, addr)
+ tt := (*sliceType)(unsafe.Pointer(v.typ))
+ typ := toCommonType(tt.elem)
+ fl |= flag(typ.Kind()) << flagKindShift
+ val := unsafe.Pointer(s.Data + uintptr(i)*typ.size)
+ return Value{typ, val, fl}
}
-
- panic("not reached")
+ panic(&ValueError{"reflect.Value.Index", k})
}
// Int returns v's underlying value, as an int64.
// It panics if v's Kind is not Int, Int8, Int16, Int32, or Int64.
func (v Value) Int() int64 {
- iv := v.internal()
- switch iv.kind {
+ k := v.kind()
+ var p unsafe.Pointer
+ if v.flag&flagIndir != 0 {
+ p = v.val
+ } else {
+ // The escape analysis is good enough that &v.val
+ // does not trigger a heap allocation.
+ p = unsafe.Pointer(&v.val)
+ }
+ switch k {
case Int:
- return int64(*(*int)(iv.addr))
+ return int64(*(*int)(p))
case Int8:
- return int64(*(*int8)(iv.addr))
+ return int64(*(*int8)(p))
case Int16:
- return int64(*(*int16)(iv.addr))
+ return int64(*(*int16)(p))
case Int32:
- return int64(*(*int32)(iv.addr))
+ return int64(*(*int32)(p))
case Int64:
- return *(*int64)(iv.addr)
+ return int64(*(*int64)(p))
}
- panic(&ValueError{"reflect.Value.Int", iv.kind})
+ panic(&ValueError{"reflect.Value.Int", k})
}
// CanInterface returns true if Interface can be used without panicking.
func (v Value) CanInterface() bool {
- iv := v.internal()
- if iv.kind == Invalid {
- panic(&ValueError{"reflect.Value.CanInterface", iv.kind})
+ if v.flag == 0 {
+ panic(&ValueError{"reflect.Value.CanInterface", Invalid})
}
- return v.InternalMethod == 0 && iv.flag&flagRO == 0
+ return v.flag&(flagMethod|flagRO) == 0
}
// Interface returns v's value as an interface{}.
@@ -876,75 +802,72 @@ func (v Value) Interface() interface{} {
}
func valueInterface(v Value, safe bool) interface{} {
- iv := v.internal()
- return iv.valueInterface(safe)
-}
-
-func (iv internalValue) valueInterface(safe bool) interface{} {
- if iv.kind == 0 {
- panic(&ValueError{"reflect.Value.Interface", iv.kind})
+ if v.flag == 0 {
+ panic(&ValueError{"reflect.Value.Interface", 0})
}
- if iv.method {
+ if v.flag&flagMethod != 0 {
panic("reflect.Value.Interface: cannot create interface value for method with bound receiver")
}
- if safe && iv.flag&flagRO != 0 {
+ if safe && v.flag&flagRO != 0 {
// Do not allow access to unexported values via Interface,
// because they might be pointers that should not be
// writable or methods or function that should not be callable.
panic("reflect.Value.Interface: cannot return value obtained from unexported field or method")
}
- if iv.kind == Interface {
+
+ k := v.kind()
+ if k == Interface {
// Special case: return the element inside the interface.
- // Won't recurse further because an interface cannot contain an interface.
- if iv.IsNil() {
- return nil
+ // Empty interface has one layout, all interfaces with
+ // methods have a second layout.
+ if v.NumMethod() == 0 {
+ return *(*interface{})(v.val)
}
- return iv.Elem().Interface()
+ return *(*interface {
+ M()
+ })(v.val)
}
// Non-interface value.
var eface emptyInterface
- eface.typ = iv.typ.runtimeType()
- eface.word = iv.word
+ eface.typ = v.typ.runtimeType()
+ eface.word = v.iword()
return *(*interface{})(unsafe.Pointer(&eface))
}
// InterfaceData returns the interface v's value as a uintptr pair.
// It panics if v's Kind is not Interface.
func (v Value) InterfaceData() [2]uintptr {
- iv := v.internal()
- iv.mustBe(Interface)
+ v.mustBe(Interface)
// We treat this as a read operation, so we allow
// it even for unexported data, because the caller
// has to import "unsafe" to turn it into something
// that can be abused.
- return *(*[2]uintptr)(iv.addr)
+ // Interface value is always bigger than a word; assume flagIndir.
+ return *(*[2]uintptr)(v.val)
}
// IsNil returns true if v is a nil value.
// It panics if v's Kind is not Chan, Func, Interface, Map, Ptr, or Slice.
func (v Value) IsNil() bool {
- return v.internal().IsNil()
-}
-
-func (iv internalValue) IsNil() bool {
- switch iv.kind {
- case Ptr:
- if iv.method {
+ k := v.kind()
+ switch k {
+ case Chan, Func, Map, Ptr:
+ if v.flag&flagMethod != 0 {
panic("reflect: IsNil of method Value")
}
- return iv.word == 0
- case Chan, Func, Map:
- if iv.method {
- panic("reflect: IsNil of method Value")
+ ptr := v.val
+ if v.flag&flagIndir != 0 {
+ ptr = *(*unsafe.Pointer)(ptr)
}
- return *(*uintptr)(iv.addr) == 0
+ return ptr == nil
case Interface, Slice:
// Both interface and slice are nil if first word is 0.
- return *(*uintptr)(iv.addr) == 0
+ // Both are always bigger than a word; assume flagIndir.
+ return *(*unsafe.Pointer)(v.val) == nil
}
- panic(&ValueError{"reflect.Value.IsNil", iv.kind})
+ panic(&ValueError{"reflect.Value.IsNil", k})
}
// IsValid returns true if v represents a value.
@@ -953,32 +876,35 @@ func (iv internalValue) IsNil() bool {
// Most functions and methods never return an invalid value.
// If one does, its documentation states the conditions explicitly.
func (v Value) IsValid() bool {
- return v.Internal != nil
+ return v.flag != 0
}
// Kind returns v's Kind.
// If v is the zero Value (IsValid returns false), Kind returns Invalid.
func (v Value) Kind() Kind {
- return v.internal().kind
+ return v.kind()
}
// Len returns v's length.
// It panics if v's Kind is not Array, Chan, Map, Slice, or String.
func (v Value) Len() int {
- iv := v.internal()
- switch iv.kind {
+ k := v.kind()
+ switch k {
case Array:
- return iv.typ.Len()
+ tt := (*arrayType)(unsafe.Pointer(v.typ))
+ return int(tt.len)
case Chan:
- return int(chanlen(*(*iword)(iv.addr)))
+ return int(chanlen(*(*iword)(v.iword())))
case Map:
- return int(maplen(*(*iword)(iv.addr)))
+ return int(maplen(*(*iword)(v.iword())))
case Slice:
- return (*SliceHeader)(iv.addr).Len
+ // Slice is bigger than a word; assume flagIndir.
+ return (*SliceHeader)(v.val).Len
case String:
- return (*StringHeader)(iv.addr).Len
+ // String is bigger than a word; assume flagIndir.
+ return (*StringHeader)(v.val).Len
}
- panic(&ValueError{"reflect.Value.Len", iv.kind})
+ panic(&ValueError{"reflect.Value.Len", k})
}
// MapIndex returns the value associated with key in the map v.
@@ -986,29 +912,29 @@ func (v Value) Len() int {
// It returns the zero Value if key is not found in the map or if v represents a nil map.
// As in Go, the key's value must be assignable to the map's key type.
func (v Value) MapIndex(key Value) Value {
- iv := v.internal()
- iv.mustBe(Map)
- typ := iv.typ.toType()
+ v.mustBe(Map)
+ tt := (*mapType)(unsafe.Pointer(v.typ))
- // Do not require ikey to be exported, so that DeepEqual
+ // Do not require key to be exported, so that DeepEqual
// and other programs can use all the keys returned by
// MapKeys as arguments to MapIndex. If either the map
// or the key is unexported, though, the result will be
- // considered unexported.
-
- ikey := key.internal()
- ikey = convertForAssignment("reflect.Value.MapIndex", nil, typ.Key(), ikey)
- if iv.word == 0 {
- return Value{}
- }
+ // considered unexported. This is consistent with the
+ // behavior for structs, which allow read but not write
+ // of unexported fields.
+ key = key.assignTo("reflect.Value.MapIndex", toCommonType(tt.key), nil)
- flag := (iv.flag | ikey.flag) & flagRO
- elemType := typ.Elem()
- elemWord, ok := mapaccess(typ.runtimeType(), *(*iword)(iv.addr), ikey.word)
+ word, ok := mapaccess(v.typ.runtimeType(), *(*iword)(v.iword()), key.iword())
if !ok {
return Value{}
}
- return valueFromIword(flag, elemType, elemWord)
+ typ := toCommonType(tt.elem)
+ fl := (v.flag | key.flag) & flagRO
+ if typ.Kind() != Ptr && typ.Kind() != UnsafePointer {
+ fl |= flagIndir
+ }
+ fl |= flag(typ.Kind()) << flagKindShift
+ return Value{typ, unsafe.Pointer(word), fl}
}
// MapKeys returns a slice containing all the keys present in the map,
@@ -1016,17 +942,22 @@ func (v Value) MapIndex(key Value) Value {
// It panics if v's Kind is not Map.
// It returns an empty slice if v represents a nil map.
func (v Value) MapKeys() []Value {
- iv := v.internal()
- iv.mustBe(Map)
- keyType := iv.typ.Key()
+ v.mustBe(Map)
+ tt := (*mapType)(unsafe.Pointer(v.typ))
+ keyType := toCommonType(tt.key)
+
+ fl := v.flag & flagRO
+ fl |= flag(keyType.Kind()) << flagKindShift
+ if keyType.Kind() != Ptr && keyType.Kind() != UnsafePointer {
+ fl |= flagIndir
+ }
- flag := iv.flag & flagRO
- m := *(*iword)(iv.addr)
+ m := *(*iword)(v.iword())
mlen := int32(0)
- if m != 0 {
+ if m != nil {
mlen = maplen(m)
}
- it := mapiterinit(iv.typ.runtimeType(), m)
+ it := mapiterinit(v.typ.runtimeType(), m)
a := make([]Value, mlen)
var i int
for i = 0; i < len(a); i++ {
@@ -1034,7 +965,7 @@ func (v Value) MapKeys() []Value {
if !ok {
break
}
- a[i] = valueFromIword(flag, keyType, keyWord)
+ a[i] = Value{keyType, unsafe.Pointer(keyWord), fl}
mapiternext(it)
}
return a[:i]
@@ -1045,23 +976,27 @@ func (v Value) MapKeys() []Value {
// a receiver; the returned function will always use v as the receiver.
// Method panics if i is out of range.
func (v Value) Method(i int) Value {
- iv := v.internal()
- if iv.kind == Invalid {
+ if v.typ == nil {
panic(&ValueError{"reflect.Value.Method", Invalid})
}
- if i < 0 || i >= iv.typ.NumMethod() {
+ if v.flag&flagMethod != 0 || i < 0 || i >= v.typ.NumMethod() {
panic("reflect: Method index out of range")
}
- return Value{v.Internal, i + 1}
+ fl := v.flag & (flagRO | flagAddr | flagIndir)
+ fl |= flag(Func) << flagKindShift
+ fl |= flag(i)<<flagMethodShift | flagMethod
+ return Value{v.typ, v.val, fl}
}
// NumMethod returns the number of methods in the value's method set.
func (v Value) NumMethod() int {
- iv := v.internal()
- if iv.kind == Invalid {
+ if v.typ == nil {
panic(&ValueError{"reflect.Value.NumMethod", Invalid})
}
- return iv.typ.NumMethod()
+ if v.flag&flagMethod != 0 {
+ return 0
+ }
+ return v.typ.NumMethod()
}
// MethodByName returns a function value corresponding to the method
@@ -1070,49 +1005,51 @@ func (v Value) NumMethod() int {
// a receiver; the returned function will always use v as the receiver.
// It returns the zero Value if no method was found.
func (v Value) MethodByName(name string) Value {
- iv := v.internal()
- if iv.kind == Invalid {
+ if v.typ == nil {
panic(&ValueError{"reflect.Value.MethodByName", Invalid})
}
- m, ok := iv.typ.MethodByName(name)
- if ok {
- return Value{v.Internal, m.Index + 1}
+ if v.flag&flagMethod != 0 {
+ return Value{}
}
- return Value{}
+ m, ok := v.typ.MethodByName(name)
+ if !ok {
+ return Value{}
+ }
+ return v.Method(m.Index)
}
// NumField returns the number of fields in the struct v.
// It panics if v's Kind is not Struct.
func (v Value) NumField() int {
- iv := v.internal()
- iv.mustBe(Struct)
- return iv.typ.NumField()
+ v.mustBe(Struct)
+ tt := (*structType)(unsafe.Pointer(v.typ))
+ return len(tt.fields)
}
// OverflowComplex returns true if the complex128 x cannot be represented by v's type.
// It panics if v's Kind is not Complex64 or Complex128.
func (v Value) OverflowComplex(x complex128) bool {
- iv := v.internal()
- switch iv.kind {
+ k := v.kind()
+ switch k {
case Complex64:
return overflowFloat32(real(x)) || overflowFloat32(imag(x))
case Complex128:
return false
}
- panic(&ValueError{"reflect.Value.OverflowComplex", iv.kind})
+ panic(&ValueError{"reflect.Value.OverflowComplex", k})
}
// OverflowFloat returns true if the float64 x cannot be represented by v's type.
// It panics if v's Kind is not Float32 or Float64.
func (v Value) OverflowFloat(x float64) bool {
- iv := v.internal()
- switch iv.kind {
+ k := v.kind()
+ switch k {
case Float32:
return overflowFloat32(x)
case Float64:
return false
}
- panic(&ValueError{"reflect.Value.OverflowFloat", iv.kind})
+ panic(&ValueError{"reflect.Value.OverflowFloat", k})
}
func overflowFloat32(x float64) bool {
@@ -1125,27 +1062,27 @@ func overflowFloat32(x float64) bool {
// OverflowInt returns true if the int64 x cannot be represented by v's type.
// It panics if v's Kind is not Int, Int8, int16, Int32, or Int64.
func (v Value) OverflowInt(x int64) bool {
- iv := v.internal()
- switch iv.kind {
+ k := v.kind()
+ switch k {
case Int, Int8, Int16, Int32, Int64:
- bitSize := iv.typ.size * 8
+ bitSize := v.typ.size * 8
trunc := (x << (64 - bitSize)) >> (64 - bitSize)
return x != trunc
}
- panic(&ValueError{"reflect.Value.OverflowInt", iv.kind})
+ panic(&ValueError{"reflect.Value.OverflowInt", k})
}
// OverflowUint returns true if the uint64 x cannot be represented by v's type.
// It panics if v's Kind is not Uint, Uintptr, Uint8, Uint16, Uint32, or Uint64.
func (v Value) OverflowUint(x uint64) bool {
- iv := v.internal()
- switch iv.kind {
+ k := v.kind()
+ switch k {
case Uint, Uintptr, Uint8, Uint16, Uint32, Uint64:
- bitSize := iv.typ.size * 8
+ bitSize := v.typ.size * 8
trunc := (x << (64 - bitSize)) >> (64 - bitSize)
return x != trunc
}
- panic(&ValueError{"reflect.Value.OverflowUint", iv.kind})
+ panic(&ValueError{"reflect.Value.OverflowUint", k})
}
// Pointer returns v's value as a uintptr.
@@ -1154,22 +1091,21 @@ func (v Value) OverflowUint(x uint64) bool {
// without importing the unsafe package explicitly.
// It panics if v's Kind is not Chan, Func, Map, Ptr, Slice, or UnsafePointer.
func (v Value) Pointer() uintptr {
- iv := v.internal()
- switch iv.kind {
- case Ptr, UnsafePointer:
- if iv.kind == Func && v.InternalMethod != 0 {
+ k := v.kind()
+ switch k {
+ case Chan, Func, Map, Ptr, UnsafePointer:
+ if k == Func && v.flag&flagMethod != 0 {
panic("reflect.Value.Pointer of method Value")
}
- return uintptr(iv.word)
- case Chan, Func, Map:
- if iv.kind == Func && v.InternalMethod != 0 {
- panic("reflect.Value.Pointer of method Value")
+ p := v.val
+ if v.flag&flagIndir != 0 {
+ p = *(*unsafe.Pointer)(p)
}
- return *(*uintptr)(iv.addr)
+ return uintptr(p)
case Slice:
- return (*SliceHeader)(iv.addr).Data
+ return (*SliceHeader)(v.val).Data
}
- panic(&ValueError{"reflect.Value.Pointer", iv.kind})
+ panic(&ValueError{"reflect.Value.Pointer", k})
}
// Recv receives and returns a value from the channel v.
@@ -1178,25 +1114,26 @@ func (v Value) Pointer() uintptr {
// The boolean value ok is true if the value x corresponds to a send
// on the channel, false if it is a zero value received because the channel is closed.
func (v Value) Recv() (x Value, ok bool) {
- iv := v.internal()
- iv.mustBe(Chan)
- iv.mustBeExported()
- return iv.recv(false)
+ v.mustBe(Chan)
+ v.mustBeExported()
+ return v.recv(false)
}
-// internal recv, possibly non-blocking (nb)
-func (iv internalValue) recv(nb bool) (val Value, ok bool) {
- t := iv.typ.toType()
- if t.ChanDir()&RecvDir == 0 {
+// internal recv, possibly non-blocking (nb).
+// v is known to be a channel.
+func (v Value) recv(nb bool) (val Value, ok bool) {
+ tt := (*chanType)(unsafe.Pointer(v.typ))
+ if ChanDir(tt.dir)&RecvDir == 0 {
panic("recv on send-only channel")
}
- ch := *(*iword)(iv.addr)
- if ch == 0 {
- panic("recv on nil channel")
- }
- valWord, selected, ok := chanrecv(iv.typ.runtimeType(), ch, nb)
+ word, selected, ok := chanrecv(v.typ.runtimeType(), *(*iword)(v.iword()), nb)
if selected {
- val = valueFromIword(0, t.Elem(), valWord)
+ typ := toCommonType(tt.elem)
+ fl := flag(typ.Kind()) << flagKindShift
+ if typ.Kind() != Ptr && typ.Kind() != UnsafePointer {
+ fl |= flagIndir
+ }
+ val = Value{typ, unsafe.Pointer(word), fl}
}
return
}
@@ -1205,128 +1142,114 @@ func (iv internalValue) recv(nb bool) (val Value, ok bool) {
// It panics if v's kind is not Chan or if x's type is not the same type as v's element type.
// As in Go, x's value must be assignable to the channel's element type.
func (v Value) Send(x Value) {
- iv := v.internal()
- iv.mustBe(Chan)
- iv.mustBeExported()
- iv.send(x, false)
+ v.mustBe(Chan)
+ v.mustBeExported()
+ v.send(x, false)
}
-// internal send, possibly non-blocking
-func (iv internalValue) send(x Value, nb bool) (selected bool) {
- t := iv.typ.toType()
- if t.ChanDir()&SendDir == 0 {
+// internal send, possibly non-blocking.
+// v is known to be a channel.
+func (v Value) send(x Value, nb bool) (selected bool) {
+ tt := (*chanType)(unsafe.Pointer(v.typ))
+ if ChanDir(tt.dir)&SendDir == 0 {
panic("send on recv-only channel")
}
- ix := x.internal()
- ix.mustBeExported() // do not let unexported x leak
- ix = convertForAssignment("reflect.Value.Send", nil, t.Elem(), ix)
- ch := *(*iword)(iv.addr)
- if ch == 0 {
- panic("send on nil channel")
- }
- return chansend(iv.typ.runtimeType(), ch, ix.word, nb)
+ x.mustBeExported()
+ x = x.assignTo("reflect.Value.Send", toCommonType(tt.elem), nil)
+ return chansend(v.typ.runtimeType(), *(*iword)(v.iword()), x.iword(), nb)
}
// Set assigns x to the value v.
// It panics if CanSet returns false.
// As in Go, x's value must be assignable to v's type.
func (v Value) Set(x Value) {
- iv := v.internal()
- ix := x.internal()
-
- iv.mustBeAssignable()
- ix.mustBeExported() // do not let unexported x leak
-
- ix = convertForAssignment("reflect.Set", iv.addr, iv.typ, ix)
-
- n := ix.typ.size
- if Kind(ix.typ.kind) == Ptr || Kind(ix.typ.kind) == UnsafePointer {
- storeIword(iv.addr, ix.word, n)
+ v.mustBeAssignable()
+ x.mustBeExported() // do not let unexported x leak
+ var target *interface{}
+ if v.kind() == Interface {
+ target = (*interface{})(v.val)
+ }
+ x = x.assignTo("reflect.Set", v.typ, target)
+ if x.flag&flagIndir != 0 {
+ memmove(v.val, x.val, v.typ.size)
} else {
- memmove(iv.addr, ix.addr, n)
+ storeIword(v.val, iword(x.val), v.typ.size)
}
}
// SetBool sets v's underlying value.
// It panics if v's Kind is not Bool or if CanSet() is false.
func (v Value) SetBool(x bool) {
- iv := v.internal()
- iv.mustBeAssignable()
- iv.mustBe(Bool)
- *(*bool)(iv.addr) = x
+ v.mustBeAssignable()
+ v.mustBe(Bool)
+ *(*bool)(v.val) = x
}
// SetBytes sets v's underlying value.
// It panics if v's underlying value is not a slice of bytes.
func (v Value) SetBytes(x []byte) {
- iv := v.internal()
- iv.mustBeAssignable()
- iv.mustBe(Slice)
- typ := iv.typ.toType()
- if typ.Elem().Kind() != Uint8 {
+ v.mustBeAssignable()
+ v.mustBe(Slice)
+ if v.typ.Elem().Kind() != Uint8 {
panic("reflect.Value.SetBytes of non-byte slice")
}
- *(*[]byte)(iv.addr) = x
+ *(*[]byte)(v.val) = x
}
// SetComplex sets v's underlying value to x.
// It panics if v's Kind is not Complex64 or Complex128, or if CanSet() is false.
func (v Value) SetComplex(x complex128) {
- iv := v.internal()
- iv.mustBeAssignable()
- switch iv.kind {
+ v.mustBeAssignable()
+ switch k := v.kind(); k {
default:
- panic(&ValueError{"reflect.Value.SetComplex", iv.kind})
+ panic(&ValueError{"reflect.Value.SetComplex", k})
case Complex64:
- *(*complex64)(iv.addr) = complex64(x)
+ *(*complex64)(v.val) = complex64(x)
case Complex128:
- *(*complex128)(iv.addr) = x
+ *(*complex128)(v.val) = x
}
}
// SetFloat sets v's underlying value to x.
// It panics if v's Kind is not Float32 or Float64, or if CanSet() is false.
func (v Value) SetFloat(x float64) {
- iv := v.internal()
- iv.mustBeAssignable()
- switch iv.kind {
+ v.mustBeAssignable()
+ switch k := v.kind(); k {
default:
- panic(&ValueError{"reflect.Value.SetFloat", iv.kind})
+ panic(&ValueError{"reflect.Value.SetFloat", k})
case Float32:
- *(*float32)(iv.addr) = float32(x)
+ *(*float32)(v.val) = float32(x)
case Float64:
- *(*float64)(iv.addr) = x
+ *(*float64)(v.val) = x
}
}
// SetInt sets v's underlying value to x.
// It panics if v's Kind is not Int, Int8, Int16, Int32, or Int64, or if CanSet() is false.
func (v Value) SetInt(x int64) {
- iv := v.internal()
- iv.mustBeAssignable()
- switch iv.kind {
+ v.mustBeAssignable()
+ switch k := v.kind(); k {
default:
- panic(&ValueError{"reflect.Value.SetInt", iv.kind})
+ panic(&ValueError{"reflect.Value.SetInt", k})
case Int:
- *(*int)(iv.addr) = int(x)
+ *(*int)(v.val) = int(x)
case Int8:
- *(*int8)(iv.addr) = int8(x)
+ *(*int8)(v.val) = int8(x)
case Int16:
- *(*int16)(iv.addr) = int16(x)
+ *(*int16)(v.val) = int16(x)
case Int32:
- *(*int32)(iv.addr) = int32(x)
+ *(*int32)(v.val) = int32(x)
case Int64:
- *(*int64)(iv.addr) = x
+ *(*int64)(v.val) = x
}
}
// SetLen sets v's length to n.
// It panics if v's Kind is not Slice.
func (v Value) SetLen(n int) {
- iv := v.internal()
- iv.mustBeAssignable()
- iv.mustBe(Slice)
- s := (*SliceHeader)(iv.addr)
+ v.mustBeAssignable()
+ v.mustBe(Slice)
+ s := (*SliceHeader)(v.val)
if n < 0 || n > int(s.Cap) {
panic("reflect: slice length out of range in SetLen")
}
@@ -1339,88 +1262,84 @@ func (v Value) SetLen(n int) {
// As in Go, key's value must be assignable to the map's key type,
// and val's value must be assignable to the map's value type.
func (v Value) SetMapIndex(key, val Value) {
- iv := v.internal()
- ikey := key.internal()
- ival := val.internal()
-
- iv.mustBe(Map)
- iv.mustBeExported()
-
- ikey.mustBeExported()
- ikey = convertForAssignment("reflect.Value.SetMapIndex", nil, iv.typ.Key(), ikey)
-
- if ival.kind != Invalid {
- ival.mustBeExported()
- ival = convertForAssignment("reflect.Value.SetMapIndex", nil, iv.typ.Elem(), ival)
+ v.mustBe(Map)
+ v.mustBeExported()
+ key.mustBeExported()
+ tt := (*mapType)(unsafe.Pointer(v.typ))
+ key = key.assignTo("reflect.Value.SetMapIndex", toCommonType(tt.key), nil)
+ if val.typ != nil {
+ val.mustBeExported()
+ val = val.assignTo("reflect.Value.SetMapIndex", toCommonType(tt.elem), nil)
}
-
- mapassign(iv.typ.runtimeType(), *(*iword)(iv.addr), ikey.word, ival.word, ival.kind != Invalid)
+ mapassign(v.typ.runtimeType(), *(*iword)(v.iword()), key.iword(), val.iword(), val.typ != nil)
}
// SetUint sets v's underlying value to x.
// It panics if v's Kind is not Uint, Uintptr, Uint8, Uint16, Uint32, or Uint64, or if CanSet() is false.
func (v Value) SetUint(x uint64) {
- iv := v.internal()
- iv.mustBeAssignable()
- switch iv.kind {
+ v.mustBeAssignable()
+ switch k := v.kind(); k {
default:
- panic(&ValueError{"reflect.Value.SetUint", iv.kind})
+ panic(&ValueError{"reflect.Value.SetUint", k})
case Uint:
- *(*uint)(iv.addr) = uint(x)
+ *(*uint)(v.val) = uint(x)
case Uint8:
- *(*uint8)(iv.addr) = uint8(x)
+ *(*uint8)(v.val) = uint8(x)
case Uint16:
- *(*uint16)(iv.addr) = uint16(x)
+ *(*uint16)(v.val) = uint16(x)
case Uint32:
- *(*uint32)(iv.addr) = uint32(x)
+ *(*uint32)(v.val) = uint32(x)
case Uint64:
- *(*uint64)(iv.addr) = x
+ *(*uint64)(v.val) = x
case Uintptr:
- *(*uintptr)(iv.addr) = uintptr(x)
+ *(*uintptr)(v.val) = uintptr(x)
}
}
// SetPointer sets the unsafe.Pointer value v to x.
// It panics if v's Kind is not UnsafePointer.
func (v Value) SetPointer(x unsafe.Pointer) {
- iv := v.internal()
- iv.mustBeAssignable()
- iv.mustBe(UnsafePointer)
- *(*unsafe.Pointer)(iv.addr) = x
+ v.mustBeAssignable()
+ v.mustBe(UnsafePointer)
+ *(*unsafe.Pointer)(v.val) = x
}
// SetString sets v's underlying value to x.
// It panics if v's Kind is not String or if CanSet() is false.
func (v Value) SetString(x string) {
- iv := v.internal()
- iv.mustBeAssignable()
- iv.mustBe(String)
- *(*string)(iv.addr) = x
+ v.mustBeAssignable()
+ v.mustBe(String)
+ *(*string)(v.val) = x
}
// Slice returns a slice of v.
// It panics if v's Kind is not Array or Slice.
func (v Value) Slice(beg, end int) Value {
- iv := v.internal()
- if iv.kind != Array && iv.kind != Slice {
- panic(&ValueError{"reflect.Value.Slice", iv.kind})
- }
- cap := v.Cap()
- if beg < 0 || end < beg || end > cap {
- panic("reflect.Value.Slice: slice index out of bounds")
- }
- var typ Type
- var base uintptr
- switch iv.kind {
+ var (
+ cap int
+ typ *sliceType
+ base unsafe.Pointer
+ )
+ switch k := v.kind(); k {
+ default:
+ panic(&ValueError{"reflect.Value.Slice", k})
case Array:
- if iv.flag&flagAddr == 0 {
+ if v.flag&flagAddr == 0 {
panic("reflect.Value.Slice: slice of unaddressable array")
}
- typ = toType((*arrayType)(unsafe.Pointer(iv.typ)).slice)
- base = uintptr(iv.addr)
+ tt := (*arrayType)(unsafe.Pointer(v.typ))
+ cap = int(tt.len)
+ typ = (*sliceType)(unsafe.Pointer(toCommonType(tt.slice)))
+ base = v.val
case Slice:
- typ = iv.typ.toType()
- base = (*SliceHeader)(iv.addr).Data
+ typ = (*sliceType)(unsafe.Pointer(v.typ))
+ s := (*SliceHeader)(v.val)
+ base = unsafe.Pointer(s.Data)
+ cap = s.Cap
+
+ }
+ if beg < 0 || end < beg || end > cap {
+ panic("reflect.Value.Slice: slice index out of bounds")
}
// Declare slice so that gc can see the base pointer in it.
@@ -1428,11 +1347,12 @@ func (v Value) Slice(beg, end int) Value {
// Reinterpret as *SliceHeader to edit.
s := (*SliceHeader)(unsafe.Pointer(&x))
- s.Data = base + uintptr(beg)*typ.Elem().Size()
+ s.Data = uintptr(base) + uintptr(beg)*toCommonType(typ.elem).Size()
s.Len = end - beg
s.Cap = end - beg
- return valueFromAddr(iv.flag&flagRO, typ, unsafe.Pointer(&x))
+ fl := v.flag&flagRO | flagIndir | flag(Slice)<<flagKindShift
+ return Value{typ.common(), unsafe.Pointer(&x), fl}
}
// String returns the string v's underlying value, as a string.
@@ -1440,16 +1360,15 @@ func (v Value) Slice(beg, end int) Value {
// Unlike the other getters, it does not panic if v's Kind is not String.
// Instead, it returns a string of the form "<T value>" where T is v's type.
func (v Value) String() string {
- iv := v.internal()
- switch iv.kind {
+ switch k := v.kind(); k {
case Invalid:
return "<invalid Value>"
case String:
- return *(*string)(iv.addr)
+ return *(*string)(v.val)
}
// If you call String on a reflect.Value of other type, it's better to
// print something than to panic. Useful in debugging.
- return "<" + iv.typ.String() + " Value>"
+ return "<" + v.typ.String() + " Value>"
}
// TryRecv attempts to receive a value from the channel v but will not block.
@@ -1458,10 +1377,9 @@ func (v Value) String() string {
// The boolean ok is true if the value x corresponds to a send
// on the channel, false if it is a zero value received because the channel is closed.
func (v Value) TryRecv() (x Value, ok bool) {
- iv := v.internal()
- iv.mustBe(Chan)
- iv.mustBeExported()
- return iv.recv(true)
+ v.mustBe(Chan)
+ v.mustBeExported()
+ return v.recv(true)
}
// TrySend attempts to send x on the channel v but will not block.
@@ -1469,54 +1387,83 @@ func (v Value) TryRecv() (x Value, ok bool) {
// It returns true if the value was sent, false otherwise.
// As in Go, x's value must be assignable to the channel's element type.
func (v Value) TrySend(x Value) bool {
- iv := v.internal()
- iv.mustBe(Chan)
- iv.mustBeExported()
- return iv.send(x, true)
+ v.mustBe(Chan)
+ v.mustBeExported()
+ return v.send(x, true)
}
// Type returns v's type.
func (v Value) Type() Type {
- t := v.internal().typ
- if t == nil {
+ f := v.flag
+ if f == 0 {
panic(&ValueError{"reflect.Value.Type", Invalid})
}
- return t.toType()
+ if f&flagMethod == 0 {
+ // Easy case
+ return v.typ.toType()
+ }
+
+ // Method value.
+ // v.typ describes the receiver, not the method type.
+ i := int(v.flag) >> flagMethodShift
+ if v.typ.Kind() == Interface {
+ // Method on interface.
+ tt := (*interfaceType)(unsafe.Pointer(v.typ))
+ if i < 0 || i >= len(tt.methods) {
+ panic("reflect: broken Value")
+ }
+ m := &tt.methods[i]
+ return toCommonType(m.typ).toType()
+ }
+ // Method on concrete type.
+ ut := v.typ.uncommon()
+ if ut == nil || i < 0 || i >= len(ut.methods) {
+ panic("reflect: broken Value")
+ }
+ m := &ut.methods[i]
+ return toCommonType(m.mtyp).toType()
}
// Uint returns v's underlying value, as a uint64.
// It panics if v's Kind is not Uint, Uintptr, Uint8, Uint16, Uint32, or Uint64.
func (v Value) Uint() uint64 {
- iv := v.internal()
- switch iv.kind {
+ k := v.kind()
+ var p unsafe.Pointer
+ if v.flag&flagIndir != 0 {
+ p = v.val
+ } else {
+ // The escape analysis is good enough that &v.val
+ // does not trigger a heap allocation.
+ p = unsafe.Pointer(&v.val)
+ }
+ switch k {
case Uint:
- return uint64(*(*uint)(iv.addr))
+ return uint64(*(*uint)(p))
case Uint8:
- return uint64(*(*uint8)(iv.addr))
+ return uint64(*(*uint8)(p))
case Uint16:
- return uint64(*(*uint16)(iv.addr))
+ return uint64(*(*uint16)(p))
case Uint32:
- return uint64(*(*uint32)(iv.addr))
- case Uintptr:
- return uint64(*(*uintptr)(iv.addr))
+ return uint64(*(*uint32)(p))
case Uint64:
- return *(*uint64)(iv.addr)
+ return uint64(*(*uint64)(p))
+ case Uintptr:
+ return uint64(*(*uintptr)(p))
}
- panic(&ValueError{"reflect.Value.Uint", iv.kind})
+ panic(&ValueError{"reflect.Value.Uint", k})
}
// UnsafeAddr returns a pointer to v's data.
// It is for advanced clients that also import the "unsafe" package.
// It panics if v is not addressable.
func (v Value) UnsafeAddr() uintptr {
- iv := v.internal()
- if iv.kind == Invalid {
- panic(&ValueError{"reflect.Value.UnsafeAddr", iv.kind})
+ if v.typ == nil {
+ panic(&ValueError{"reflect.Value.UnsafeAddr", Invalid})
}
- if iv.flag&flagAddr == 0 {
+ if v.flag&flagAddr == 0 {
panic("reflect.Value.UnsafeAddr of unaddressable value")
}
- return uintptr(iv.addr)
+ return uintptr(v.val)
}
// StringHeader is the runtime representation of a string.
@@ -1536,7 +1483,7 @@ type SliceHeader struct {
func typesMustMatch(what string, t1, t2 Type) {
if t1 != t2 {
- panic("reflect: " + what + ": " + t1.String() + " != " + t2.String())
+ panic(what + ": " + t1.String() + " != " + t2.String())
}
}
@@ -1571,7 +1518,7 @@ func grow(s Value, extra int) (Value, int, int) {
// Append appends the values x to a slice s and returns the resulting slice.
// As in Go, each x's value must be assignable to the slice's element type.
func Append(s Value, x ...Value) Value {
- s.internal().mustBe(Slice)
+ s.mustBe(Slice)
s, i0, i1 := grow(s, len(x))
for i, j := i0, 0; i < i1; i, j = i+1, j+1 {
s.Index(i).Set(x[j])
@@ -1582,8 +1529,8 @@ func Append(s Value, x ...Value) Value {
// AppendSlice appends a slice t to a slice s and returns the resulting slice.
// The slices s and t must have the same element type.
func AppendSlice(s, t Value) Value {
- s.internal().mustBe(Slice)
- t.internal().mustBe(Slice)
+ s.mustBe(Slice)
+ t.mustBe(Slice)
typesMustMatch("reflect.AppendSlice", s.Type().Elem(), t.Type().Elem())
s, i0, i1 := grow(s, t.Len())
Copy(s.Slice(i0, i1), t)
@@ -1596,23 +1543,23 @@ func AppendSlice(s, t Value) Value {
// Dst and src each must have kind Slice or Array, and
// dst and src must have the same element type.
func Copy(dst, src Value) int {
- idst := dst.internal()
- isrc := src.internal()
-
- if idst.kind != Array && idst.kind != Slice {
- panic(&ValueError{"reflect.Copy", idst.kind})
+ dk := dst.kind()
+ if dk != Array && dk != Slice {
+ panic(&ValueError{"reflect.Copy", dk})
}
- if idst.kind == Array {
- idst.mustBeAssignable()
+ if dk == Array {
+ dst.mustBeAssignable()
}
- idst.mustBeExported()
- if isrc.kind != Array && isrc.kind != Slice {
- panic(&ValueError{"reflect.Copy", isrc.kind})
+ dst.mustBeExported()
+
+ sk := src.kind()
+ if sk != Array && sk != Slice {
+ panic(&ValueError{"reflect.Copy", sk})
}
- isrc.mustBeExported()
+ src.mustBeExported()
- de := idst.typ.Elem()
- se := isrc.typ.Elem()
+ de := dst.typ.Elem()
+ se := src.typ.Elem()
typesMustMatch("reflect.Copy", de, se)
n := dst.Len()
@@ -1622,7 +1569,7 @@ func Copy(dst, src Value) int {
// If sk is an in-line array, cannot take its address.
// Instead, copy element by element.
- if isrc.addr == nil {
+ if src.flag&flagIndir == 0 {
for i := 0; i < n; i++ {
dst.Index(i).Set(src.Index(i))
}
@@ -1631,15 +1578,15 @@ func Copy(dst, src Value) int {
// Copy via memmove.
var da, sa unsafe.Pointer
- if idst.kind == Array {
- da = idst.addr
+ if dk == Array {
+ da = dst.val
} else {
- da = unsafe.Pointer((*SliceHeader)(idst.addr).Data)
+ da = unsafe.Pointer((*SliceHeader)(dst.val).Data)
}
- if isrc.kind == Array {
- sa = isrc.addr
+ if sk == Array {
+ sa = src.val
} else {
- sa = unsafe.Pointer((*SliceHeader)(isrc.addr).Data)
+ sa = unsafe.Pointer((*SliceHeader)(src.val).Data)
}
memmove(da, sa, uintptr(n)*de.Size())
return n
@@ -1653,7 +1600,7 @@ func Copy(dst, src Value) int {
// for the specified slice type, length, and capacity.
func MakeSlice(typ Type, len, cap int) Value {
if typ.Kind() != Slice {
- panic("reflect: MakeSlice of non-slice type")
+ panic("reflect.MakeSlice of non-slice type")
}
// Declare slice so that gc can see the base pointer in it.
@@ -1665,31 +1612,31 @@ func MakeSlice(typ Type, len, cap int) Value {
s.Len = len
s.Cap = cap
- return valueFromAddr(0, typ, unsafe.Pointer(&x))
+ return Value{typ.common(), unsafe.Pointer(&x), flagIndir | flag(Slice)<<flagKindShift}
}
// MakeChan creates a new channel with the specified type and buffer size.
func MakeChan(typ Type, buffer int) Value {
if typ.Kind() != Chan {
- panic("reflect: MakeChan of non-chan type")
+ panic("reflect.MakeChan of non-chan type")
}
if buffer < 0 {
- panic("MakeChan: negative buffer size")
+ panic("reflect.MakeChan: negative buffer size")
}
if typ.ChanDir() != BothDir {
- panic("MakeChan: unidirectional channel type")
+ panic("reflect.MakeChan: unidirectional channel type")
}
ch := makechan(typ.runtimeType(), uint32(buffer))
- return valueFromIword(0, typ, ch)
+ return Value{typ.common(), unsafe.Pointer(ch), flagIndir | (flag(Chan)<<flagKindShift)}
}
// MakeMap creates a new map of the specified type.
func MakeMap(typ Type) Value {
if typ.Kind() != Map {
- panic("reflect: MakeMap of non-map type")
+ panic("reflect.MakeMap of non-map type")
}
m := makemap(typ.runtimeType())
- return valueFromIword(0, typ, m)
+ return Value{typ.common(), unsafe.Pointer(m), flagIndir | (flag(Map)<<flagKindShift)}
}
// Indirect returns the value that v points to.
@@ -1719,7 +1666,12 @@ func ValueOf(i interface{}) Value {
// For an interface value with the noAddr bit set,
// the representation is identical to an empty interface.
eface := *(*emptyInterface)(unsafe.Pointer(&i))
- return packValue(0, eface.typ, eface.word)
+ typ := toCommonType(eface.typ)
+ fl := flag(typ.Kind()) << flagKindShift
+ if typ.Kind() != Ptr && typ.Kind() != UnsafePointer {
+ fl |= flagIndir
+ }
+ return Value{typ, unsafe.Pointer(eface.word), fl}
}
// Zero returns a Value representing a zero value for the specified type.
@@ -1730,10 +1682,12 @@ func Zero(typ Type) Value {
if typ == nil {
panic("reflect: Zero(nil)")
}
- if typ.Kind() == Ptr || typ.Kind() == UnsafePointer {
- return valueFromIword(0, typ, 0)
+ t := typ.common()
+ fl := flag(t.Kind()) << flagKindShift
+ if t.Kind() == Ptr || t.Kind() == UnsafePointer {
+ return Value{t, nil, fl}
}
- return valueFromAddr(0, typ, unsafe.New(typ))
+ return Value{t, unsafe.New(typ), fl | flagIndir}
}
// New returns a Value representing a pointer to a new zero value
@@ -1743,40 +1697,42 @@ func New(typ Type) Value {
panic("reflect: New(nil)")
}
ptr := unsafe.New(typ)
- return valueFromIword(0, PtrTo(typ), iword(uintptr(ptr)))
+ fl := flag(Ptr) << flagKindShift
+ return Value{typ.common().ptrTo(), ptr, fl}
}
-// convertForAssignment
-func convertForAssignment(what string, addr unsafe.Pointer, dst Type, iv internalValue) internalValue {
- if iv.method {
- panic(what + ": cannot assign method value to type " + dst.String())
+// assignTo returns a value v that can be assigned directly to typ.
+// It panics if v is not assignable to typ.
+// For a conversion to an interface type, target is a suggested scratch space to use.
+func (v Value) assignTo(context string, dst *commonType, target *interface{}) Value {
+ if v.flag&flagMethod != 0 {
+ panic(context + ": cannot assign method value to type " + dst.String())
}
- dst1 := dst.(*commonType)
- if directlyAssignable(dst1, iv.typ) {
+ switch {
+ case directlyAssignable(dst, v.typ):
// Overwrite type so that they match.
// Same memory layout, so no harm done.
- iv.typ = dst1
- return iv
- }
- if implements(dst1, iv.typ) {
- if addr == nil {
- addr = unsafe.Pointer(new(interface{}))
+ v.typ = dst
+ fl := v.flag & (flagRO | flagAddr | flagIndir)
+ fl |= flag(dst.Kind()) << flagKindShift
+ return Value{dst, v.val, fl}
+
+ case implements(dst, v.typ):
+ if target == nil {
+ target = new(interface{})
}
- x := iv.valueInterface(false)
+ x := valueInterface(v, false)
if dst.NumMethod() == 0 {
- *(*interface{})(addr) = x
+ *target = x
} else {
- ifaceE2I(dst1.runtimeType(), x, addr)
+ ifaceE2I(dst.runtimeType(), x, unsafe.Pointer(target))
}
- iv.addr = addr
- iv.word = iword(uintptr(addr))
- iv.typ = dst1
- return iv
+ return Value{dst, unsafe.Pointer(target), flagIndir | flag(Interface)<<flagKindShift}
}
// Failed.
- panic(what + ": value of type " + iv.typ.String() + " is not assignable to type " + dst.String())
+ panic(context + ": value of type " + v.typ.String() + " is not assignable to type " + dst.String())
}
// implemented in ../pkg/runtime
@@ -1787,7 +1743,7 @@ func chanrecv(t *runtime.Type, ch iword, nb bool) (val iword, selected, received
func chansend(t *runtime.Type, ch iword, val iword, nb bool) bool
func makechan(typ *runtime.Type, size uint32) (ch iword)
-func makemap(t *runtime.Type) iword
+func makemap(t *runtime.Type) (m iword)
func mapaccess(t *runtime.Type, m iword, key iword) (val iword, ok bool)
func mapassign(t *runtime.Type, m iword, key, val iword, ok bool)
func mapiterinit(t *runtime.Type, m iword) *byte
@@ -1797,3 +1753,17 @@ func maplen(m iword) int32
func call(typ *commonType, fnaddr unsafe.Pointer, isInterface bool, isMethod bool, params *unsafe.Pointer, results *unsafe.Pointer)
func ifaceE2I(t *runtime.Type, src interface{}, dst unsafe.Pointer)
+
+// Dummy annotation marking that the value x escapes,
+// for use in cases where the reflect code is so clever that
+// the compiler cannot follow.
+func escapes(x interface{}) {
+ if dummy.b {
+ dummy.x = x
+ }
+}
+
+var dummy struct {
+ b bool
+ x interface{}
+}
diff --git a/libgo/go/regexp/regexp.go b/libgo/go/regexp/regexp.go
index b906076f9eb..59f3be39d29 100644
--- a/libgo/go/regexp/regexp.go
+++ b/libgo/go/regexp/regexp.go
@@ -1,7 +1,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package regexp implements a simple regular expression library.
+// Package regexp implements regular expression search.
//
// The syntax of the regular expressions accepted is the same
// general syntax used by Perl, Python, and other languages.
diff --git a/libgo/go/strconv/decimal.go b/libgo/go/strconv/decimal.go
index f572ea4a22d..541553097bb 100644
--- a/libgo/go/strconv/decimal.go
+++ b/libgo/go/strconv/decimal.go
@@ -102,12 +102,6 @@ func (a *decimal) Assign(v uint64) {
trim(a)
}
-func newDecimal(i uint64) *decimal {
- a := new(decimal)
- a.Assign(i)
- return a
-}
-
// Maximum shift that we can do in one pass without overflow.
// Signed int has 31 bits, and we have to be able to accommodate 9<<k.
const maxShift = 27
@@ -303,32 +297,32 @@ func shouldRoundUp(a *decimal, nd int) bool {
// If nd is zero, it means we're rounding
// just to the left of the digits, as in
// 0.09 -> 0.1.
-func (a *decimal) Round(nd int) *decimal {
+func (a *decimal) Round(nd int) {
if nd < 0 || nd >= a.nd {
- return a
+ return
}
if shouldRoundUp(a, nd) {
- return a.RoundUp(nd)
+ a.RoundUp(nd)
+ } else {
+ a.RoundDown(nd)
}
- return a.RoundDown(nd)
}
// Round a down to nd digits (or fewer).
// Returns receiver for convenience.
-func (a *decimal) RoundDown(nd int) *decimal {
+func (a *decimal) RoundDown(nd int) {
if nd < 0 || nd >= a.nd {
- return a
+ return
}
a.nd = nd
trim(a)
- return a
}
// Round a up to nd digits (or fewer).
// Returns receiver for convenience.
-func (a *decimal) RoundUp(nd int) *decimal {
+func (a *decimal) RoundUp(nd int) {
if nd < 0 || nd >= a.nd {
- return a
+ return
}
// round up
@@ -337,7 +331,7 @@ func (a *decimal) RoundUp(nd int) *decimal {
if c < '9' { // can stop after this digit
a.d[i]++
a.nd = i + 1
- return a
+ return
}
}
@@ -346,7 +340,6 @@ func (a *decimal) RoundUp(nd int) *decimal {
a.d[0] = '1'
a.nd = 1
a.dp++
- return a
}
// Extract integer part, rounded appropriately.
diff --git a/libgo/go/strconv/decimal_test.go b/libgo/go/strconv/decimal_test.go
index deb2e02f610..13a127f5b2c 100644
--- a/libgo/go/strconv/decimal_test.go
+++ b/libgo/go/strconv/decimal_test.go
@@ -70,17 +70,23 @@ var roundtests = []roundTest{
func TestDecimalRound(t *testing.T) {
for i := 0; i < len(roundtests); i++ {
test := &roundtests[i]
- s := NewDecimal(test.i).RoundDown(test.nd).String()
+ d := NewDecimal(test.i)
+ d.RoundDown(test.nd)
+ s := d.String()
if s != test.down {
t.Errorf("Decimal %v RoundDown %d = %v, want %v",
test.i, test.nd, s, test.down)
}
- s = NewDecimal(test.i).Round(test.nd).String()
+ d = NewDecimal(test.i)
+ d.Round(test.nd)
+ s = d.String()
if s != test.round {
t.Errorf("Decimal %v Round %d = %v, want %v",
test.i, test.nd, s, test.down)
}
- s = NewDecimal(test.i).RoundUp(test.nd).String()
+ d = NewDecimal(test.i)
+ d.RoundUp(test.nd)
+ s = d.String()
if s != test.up {
t.Errorf("Decimal %v RoundUp %d = %v, want %v",
test.i, test.nd, s, test.up)
diff --git a/libgo/go/strconv/ftoa.go b/libgo/go/strconv/ftoa.go
index 07fe806b97d..8342b6abe79 100644
--- a/libgo/go/strconv/ftoa.go
+++ b/libgo/go/strconv/ftoa.go
@@ -98,7 +98,8 @@ func genericFtoa(bits uint64, fmt byte, prec int, flt *floatInfo) string {
// The shift is exp - flt.mantbits because mant is a 1-bit integer
// followed by a flt.mantbits fraction, and we are treating it as
// a 1+flt.mantbits-bit integer.
- d := newDecimal(mant)
+ d := new(decimal)
+ d.Assign(mant)
d.Shift(exp - int(flt.mantbits))
// Round appropriately.
@@ -184,7 +185,8 @@ func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
// d = mant << (exp - mantbits)
// Next highest floating point number is mant+1 << exp-mantbits.
// Our upper bound is halfway inbetween, mant*2+1 << exp-mantbits-1.
- upper := newDecimal(mant*2 + 1)
+ upper := new(decimal)
+ upper.Assign(mant*2 + 1)
upper.Shift(exp - int(flt.mantbits) - 1)
// d = mant << (exp - mantbits)
@@ -203,7 +205,8 @@ func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
mantlo = mant*2 - 1
explo = exp - 1
}
- lower := newDecimal(mantlo*2 + 1)
+ lower := new(decimal)
+ lower.Assign(mantlo*2 + 1)
lower.Shift(explo - int(flt.mantbits) - 1)
// The upper and lower bounds are possible outputs only if
diff --git a/libgo/go/strconv/ftoa_test.go b/libgo/go/strconv/ftoa_test.go
index 6d361a138ef..8bac5da4526 100644
--- a/libgo/go/strconv/ftoa_test.go
+++ b/libgo/go/strconv/ftoa_test.go
@@ -148,3 +148,27 @@ func TestFtoa(t *testing.T) {
}
}
}
+
+func BenchmarkFtoa64Decimal(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Ftoa64(33909, 'g', -1)
+ }
+}
+
+func BenchmarkFtoa64Float(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Ftoa64(339.7784, 'g', -1)
+ }
+}
+
+func BenchmarkFtoa64FloatExp(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Ftoa64(-5.09e75, 'g', -1)
+ }
+}
+
+func BenchmarkFtoa64Big(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Ftoa64(123456789123456789123456789, 'g', -1)
+ }
+}
diff --git a/libgo/go/strconv/internal_test.go b/libgo/go/strconv/internal_test.go
index 9a7f4f0867c..d0fa80edfb6 100644
--- a/libgo/go/strconv/internal_test.go
+++ b/libgo/go/strconv/internal_test.go
@@ -6,7 +6,11 @@
package strconv
-func NewDecimal(i uint64) *decimal { return newDecimal(i) }
+func NewDecimal(i uint64) *decimal {
+ d := new(decimal)
+ d.Assign(i)
+ return d
+}
func SetOptimize(b bool) bool {
old := optimize
diff --git a/libgo/go/strings/strings_test.go b/libgo/go/strings/strings_test.go
index 304d69a19d7..96207f5a2da 100644
--- a/libgo/go/strings/strings_test.go
+++ b/libgo/go/strings/strings_test.go
@@ -489,46 +489,47 @@ func TestSpecialCase(t *testing.T) {
func TestTrimSpace(t *testing.T) { runStringTests(t, TrimSpace, "TrimSpace", trimSpaceTests) }
var trimTests = []struct {
- f func(string, string) string
+ f string
in, cutset, out string
}{
- {Trim, "abba", "a", "bb"},
- {Trim, "abba", "ab", ""},
- {TrimLeft, "abba", "ab", ""},
- {TrimRight, "abba", "ab", ""},
- {TrimLeft, "abba", "a", "bba"},
- {TrimRight, "abba", "a", "abb"},
- {Trim, "<tag>", "<>", "tag"},
- {Trim, "* listitem", " *", "listitem"},
- {Trim, `"quote"`, `"`, "quote"},
- {Trim, "\u2C6F\u2C6F\u0250\u0250\u2C6F\u2C6F", "\u2C6F", "\u0250\u0250"},
+ {"Trim", "abba", "a", "bb"},
+ {"Trim", "abba", "ab", ""},
+ {"TrimLeft", "abba", "ab", ""},
+ {"TrimRight", "abba", "ab", ""},
+ {"TrimLeft", "abba", "a", "bba"},
+ {"TrimRight", "abba", "a", "abb"},
+ {"Trim", "<tag>", "<>", "tag"},
+ {"Trim", "* listitem", " *", "listitem"},
+ {"Trim", `"quote"`, `"`, "quote"},
+ {"Trim", "\u2C6F\u2C6F\u0250\u0250\u2C6F\u2C6F", "\u2C6F", "\u0250\u0250"},
//empty string tests
- {Trim, "abba", "", "abba"},
- {Trim, "", "123", ""},
- {Trim, "", "", ""},
- {TrimLeft, "abba", "", "abba"},
- {TrimLeft, "", "123", ""},
- {TrimLeft, "", "", ""},
- {TrimRight, "abba", "", "abba"},
- {TrimRight, "", "123", ""},
- {TrimRight, "", "", ""},
- {TrimRight, "☺\xc0", "☺", "☺\xc0"},
+ {"Trim", "abba", "", "abba"},
+ {"Trim", "", "123", ""},
+ {"Trim", "", "", ""},
+ {"TrimLeft", "abba", "", "abba"},
+ {"TrimLeft", "", "123", ""},
+ {"TrimLeft", "", "", ""},
+ {"TrimRight", "abba", "", "abba"},
+ {"TrimRight", "", "123", ""},
+ {"TrimRight", "", "", ""},
+ {"TrimRight", "☺\xc0", "☺", "☺\xc0"},
}
func TestTrim(t *testing.T) {
for _, tc := range trimTests {
- actual := tc.f(tc.in, tc.cutset)
- var name string
- switch tc.f {
- case Trim:
- name = "Trim"
- case TrimLeft:
- name = "TrimLeft"
- case TrimRight:
- name = "TrimRight"
+ name := tc.f
+ var f func(string, string) string
+ switch name {
+ case "Trim":
+ f = Trim
+ case "TrimLeft":
+ f = TrimLeft
+ case "TrimRight":
+ f = TrimRight
default:
- t.Error("Undefined trim function")
+ t.Error("Undefined trim function %s", name)
}
+ actual := f(tc.in, tc.cutset)
if actual != tc.out {
t.Errorf("%s(%q, %q) = %q; want %q", name, tc.in, tc.cutset, actual, tc.out)
}
diff --git a/libgo/go/sync/mutex.go b/libgo/go/sync/mutex.go
index 2d46c89948f..4fc02743c6e 100644
--- a/libgo/go/sync/mutex.go
+++ b/libgo/go/sync/mutex.go
@@ -6,6 +6,8 @@
// exclusion locks. Other than the Once and WaitGroup types, most are intended
// for use by low-level library routines. Higher-level synchronization is
// better done via channels and communication.
+//
+// Values containing the types defined in this package should not be copied.
package sync
import (
diff --git a/libgo/go/syscall/bpf_bsd.go b/libgo/go/syscall/bpf_bsd.go
index 06a2953e7fe..f94b7233b67 100644
--- a/libgo/go/syscall/bpf_bsd.go
+++ b/libgo/go/syscall/bpf_bsd.go
@@ -20,54 +20,54 @@ func BpfJump(code, k, jt, jf int) *BpfInsn {
return &BpfInsn{Code: uint16(code), Jt: uint8(jt), Jf: uint8(jf), K: uint32(k)}
}
-func BpfBuflen(fd int) (int, int) {
+func BpfBuflen(fd int) (int, error) {
var l int
- _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCGBLEN, uintptr(unsafe.Pointer(&l)))
- if e := int(ep); e != 0 {
- return 0, e
+ _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGBLEN, uintptr(unsafe.Pointer(&l)))
+ if err != 0 {
+ return 0, Errno(err)
}
- return l, 0
+ return l, nil
}
-func SetBpfBuflen(fd, l int) (int, int) {
- _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCSBLEN, uintptr(unsafe.Pointer(&l)))
- if e := int(ep); e != 0 {
- return 0, e
+func SetBpfBuflen(fd, l int) (int, error) {
+ _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCSBLEN, uintptr(unsafe.Pointer(&l)))
+ if err != 0 {
+ return 0, Errno(err)
}
- return l, 0
+ return l, nil
}
-func BpfDatalink(fd int) (int, int) {
+func BpfDatalink(fd int) (int, error) {
var t int
- _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCGDLT, uintptr(unsafe.Pointer(&t)))
- if e := int(ep); e != 0 {
- return 0, e
+ _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGDLT, uintptr(unsafe.Pointer(&t)))
+ if err != 0 {
+ return 0, Errno(err)
}
- return t, 0
+ return t, nil
}
-func SetBpfDatalink(fd, t int) (int, int) {
- _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCSDLT, uintptr(unsafe.Pointer(&t)))
- if e := int(ep); e != 0 {
- return 0, e
+func SetBpfDatalink(fd, t int) (int, error) {
+ _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCSDLT, uintptr(unsafe.Pointer(&t)))
+ if err != 0 {
+ return 0, Errno(err)
}
- return t, 0
+ return t, nil
}
-func SetBpfPromisc(fd, m int) int {
- _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCPROMISC, uintptr(unsafe.Pointer(&m)))
- if e := int(ep); e != 0 {
- return e
+func SetBpfPromisc(fd, m int) error {
+ _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCPROMISC, uintptr(unsafe.Pointer(&m)))
+ if err != 0 {
+ return Errno(err)
}
- return 0
+ return nil
}
-func FlushBpf(fd int) int {
- _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCFLUSH, 0)
- if e := int(ep); e != 0 {
- return e
+func FlushBpf(fd int) error {
+ _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCFLUSH, 0)
+ if err != 0 {
+ return Errno(err)
}
- return 0
+ return nil
}
type ivalue struct {
@@ -75,95 +75,95 @@ type ivalue struct {
value int16
}
-func BpfInterface(fd int, name string) (string, int) {
+func BpfInterface(fd int, name string) (string, error) {
var iv ivalue
- _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCGETIF, uintptr(unsafe.Pointer(&iv)))
- if e := int(ep); e != 0 {
- return "", e
+ _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGETIF, uintptr(unsafe.Pointer(&iv)))
+ if err != 0 {
+ return "", Errno(err)
}
- return name, 0
+ return name, nil
}
-func SetBpfInterface(fd int, name string) int {
+func SetBpfInterface(fd int, name string) error {
var iv ivalue
copy(iv.name[:], []byte(name))
- _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCSETIF, uintptr(unsafe.Pointer(&iv)))
- if e := int(ep); e != 0 {
- return e
+ _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCSETIF, uintptr(unsafe.Pointer(&iv)))
+ if err != 0 {
+ return Errno(err)
}
- return 0
+ return nil
}
-func BpfTimeout(fd int) (*Timeval, int) {
+func BpfTimeout(fd int) (*Timeval, error) {
var tv Timeval
- _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCGRTIMEOUT, uintptr(unsafe.Pointer(&tv)))
- if e := int(ep); e != 0 {
- return nil, e
+ _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGRTIMEOUT, uintptr(unsafe.Pointer(&tv)))
+ if err != 0 {
+ return nil, Errno(err)
}
- return &tv, 0
+ return &tv, nil
}
-func SetBpfTimeout(fd int, tv *Timeval) int {
- _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCSRTIMEOUT, uintptr(unsafe.Pointer(tv)))
- if e := int(ep); e != 0 {
- return e
+func SetBpfTimeout(fd int, tv *Timeval) error {
+ _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCSRTIMEOUT, uintptr(unsafe.Pointer(tv)))
+ if err != 0 {
+ return Errno(err)
}
- return 0
+ return nil
}
-func BpfStats(fd int) (*BpfStat, int) {
+func BpfStats(fd int) (*BpfStat, error) {
var s BpfStat
- _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCGSTATS, uintptr(unsafe.Pointer(&s)))
- if e := int(ep); e != 0 {
- return nil, e
+ _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGSTATS, uintptr(unsafe.Pointer(&s)))
+ if err != 0 {
+ return nil, Errno(err)
}
- return &s, 0
+ return &s, nil
}
-func SetBpfImmediate(fd, m int) int {
- _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCIMMEDIATE, uintptr(unsafe.Pointer(&m)))
- if e := int(ep); e != 0 {
- return e
+func SetBpfImmediate(fd, m int) error {
+ _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCIMMEDIATE, uintptr(unsafe.Pointer(&m)))
+ if err != 0 {
+ return Errno(err)
}
- return 0
+ return nil
}
-func SetBpf(fd int, i []BpfInsn) int {
+func SetBpf(fd int, i []BpfInsn) error {
var p BpfProgram
p.Len = uint32(len(i))
p.Insns = (*BpfInsn)(unsafe.Pointer(&i[0]))
- _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCSETF, uintptr(unsafe.Pointer(&p)))
- if e := int(ep); e != 0 {
- return e
+ _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCSETF, uintptr(unsafe.Pointer(&p)))
+ if err != 0 {
+ return Errno(err)
}
- return 0
+ return nil
}
-func CheckBpfVersion(fd int) int {
+func CheckBpfVersion(fd int) error {
var v BpfVersion
- _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCVERSION, uintptr(unsafe.Pointer(&v)))
- if e := int(ep); e != 0 {
- return e
+ _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCVERSION, uintptr(unsafe.Pointer(&v)))
+ if err != 0 {
+ return Errno(err)
}
if v.Major != BPF_MAJOR_VERSION || v.Minor != BPF_MINOR_VERSION {
return EINVAL
}
- return 0
+ return nil
}
-func BpfHeadercmpl(fd int) (int, int) {
+func BpfHeadercmpl(fd int) (int, error) {
var f int
- _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCGHDRCMPLT, uintptr(unsafe.Pointer(&f)))
- if e := int(ep); e != 0 {
- return 0, e
+ _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGHDRCMPLT, uintptr(unsafe.Pointer(&f)))
+ if err != 0 {
+ return 0, Errno(err)
}
- return f, 0
+ return f, nil
}
-func SetBpfHeadercmpl(fd, f int) int {
- _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCSHDRCMPLT, uintptr(unsafe.Pointer(&f)))
- if e := int(ep); e != 0 {
- return e
+func SetBpfHeadercmpl(fd, f int) error {
+ _, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCSHDRCMPLT, uintptr(unsafe.Pointer(&f)))
+ if err != 0 {
+ return Errno(err)
}
- return 0
+ return nil
}
diff --git a/libgo/go/syscall/env_plan9.go b/libgo/go/syscall/env_plan9.go
new file mode 100644
index 00000000000..518573318ef
--- /dev/null
+++ b/libgo/go/syscall/env_plan9.go
@@ -0,0 +1,74 @@
+// 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.
+
+// Plan 9 environment variables.
+
+package syscall
+
+import "errors"
+
+func Getenv(key string) (value string, found bool) {
+ if len(key) == 0 {
+ return "", false
+ }
+ f, e := Open("/env/"+key, O_RDONLY)
+ if e != nil {
+ return "", false
+ }
+ defer Close(f)
+
+ l, _ := Seek(f, 0, 2)
+ Seek(f, 0, 0)
+ buf := make([]byte, l)
+ n, e := Read(f, buf)
+ if e != nil {
+ return "", false
+ }
+
+ if n > 0 && buf[n-1] == 0 {
+ buf = buf[:n-1]
+ }
+ return string(buf), true
+}
+
+func Setenv(key, value string) error {
+ if len(key) == 0 {
+ return errors.New("bad arg in system call")
+ }
+
+ f, e := Create("/env/"+key, O_RDWR, 0666)
+ if e != nil {
+ return e
+ }
+ defer Close(f)
+
+ _, e = Write(f, []byte(value))
+ return nil
+}
+
+func Clearenv() {
+ RawSyscall(SYS_RFORK, RFCENVG, 0, 0)
+}
+
+func Environ() []string {
+ env := make([]string, 0, 100)
+
+ f, e := Open("/env", O_RDONLY)
+ if e != nil {
+ panic(e)
+ }
+ defer Close(f)
+
+ names, e := readdirnames(f)
+ if e != nil {
+ panic(e)
+ }
+
+ for _, k := range names {
+ if v, ok := Getenv(k); ok {
+ env = append(env, k+"="+v)
+ }
+ }
+ return env[0:len(env)]
+}
diff --git a/libgo/go/syscall/env_unix.go b/libgo/go/syscall/env_unix.go
new file mode 100644
index 00000000000..df259097c6a
--- /dev/null
+++ b/libgo/go/syscall/env_unix.go
@@ -0,0 +1,85 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin freebsd linux openbsd
+
+// Unix environment variables.
+
+package syscall
+
+import "sync"
+
+var env map[string]string
+var envOnce sync.Once
+var Envs []string // provided by runtime
+
+func setenv_c(k, v string)
+
+func copyenv() {
+ env = make(map[string]string)
+ for _, s := range Envs {
+ for j := 0; j < len(s); j++ {
+ if s[j] == '=' {
+ env[s[0:j]] = s[j+1:]
+ break
+ }
+ }
+ }
+}
+
+var envLock sync.RWMutex
+
+func Getenv(key string) (value string, found bool) {
+ envOnce.Do(copyenv)
+ if len(key) == 0 {
+ return "", false
+ }
+
+ envLock.RLock()
+ defer envLock.RUnlock()
+
+ v, ok := env[key]
+ if !ok {
+ return "", false
+ }
+ return v, true
+}
+
+func Setenv(key, value string) error {
+ envOnce.Do(copyenv)
+ if len(key) == 0 {
+ return EINVAL
+ }
+
+ envLock.Lock()
+ defer envLock.Unlock()
+
+ env[key] = value
+ setenv_c(key, value) // is a no-op if cgo isn't loaded
+ return nil
+}
+
+func Clearenv() {
+ envOnce.Do(copyenv) // prevent copyenv in Getenv/Setenv
+
+ envLock.Lock()
+ defer envLock.Unlock()
+
+ env = make(map[string]string)
+
+ // TODO(bradfitz): pass through to C
+}
+
+func Environ() []string {
+ envOnce.Do(copyenv)
+ envLock.RLock()
+ defer envLock.RUnlock()
+ a := make([]string, len(env))
+ i := 0
+ for k, v := range env {
+ a[i] = k + "=" + v
+ i++
+ }
+ return a
+}
diff --git a/libgo/go/syscall/env_windows.go b/libgo/go/syscall/env_windows.go
new file mode 100644
index 00000000000..8308f10a2dc
--- /dev/null
+++ b/libgo/go/syscall/env_windows.go
@@ -0,0 +1,77 @@
+// Copyright 2010 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.
+
+// Windows environment variables.
+
+package syscall
+
+import (
+ "unicode/utf16"
+ "unsafe"
+)
+
+func Getenv(key string) (value string, found bool) {
+ b := make([]uint16, 100)
+ n, e := GetEnvironmentVariable(StringToUTF16Ptr(key), &b[0], uint32(len(b)))
+ if n == 0 && e == ERROR_ENVVAR_NOT_FOUND {
+ return "", false
+ }
+ if n > uint32(len(b)) {
+ b = make([]uint16, n)
+ n, e = GetEnvironmentVariable(StringToUTF16Ptr(key), &b[0], uint32(len(b)))
+ if n > uint32(len(b)) {
+ n = 0
+ }
+ }
+ if n == 0 {
+ return "", false
+ }
+ return string(utf16.Decode(b[0:n])), true
+}
+
+func Setenv(key, value string) error {
+ var v *uint16
+ if len(value) > 0 {
+ v = StringToUTF16Ptr(value)
+ }
+ e := SetEnvironmentVariable(StringToUTF16Ptr(key), v)
+ if e != nil {
+ return e
+ }
+ return nil
+}
+
+func Clearenv() {
+ for _, s := range Environ() {
+ // Environment variables can begin with =
+ // so start looking for the separator = at j=1.
+ // http://blogs.msdn.com/b/oldnewthing/archive/2010/05/06/10008132.aspx
+ for j := 1; j < len(s); j++ {
+ if s[j] == '=' {
+ Setenv(s[0:j], "")
+ break
+ }
+ }
+ }
+}
+
+func Environ() []string {
+ s, e := GetEnvironmentStrings()
+ if e != nil {
+ return nil
+ }
+ defer FreeEnvironmentStrings(s)
+ r := make([]string, 0, 50) // Empty with room to grow.
+ for from, i, p := 0, 0, (*[1 << 24]uint16)(unsafe.Pointer(s)); true; i++ {
+ if p[i] == 0 {
+ // empty string marks the end
+ if i <= from {
+ break
+ }
+ r = append(r, string(utf16.Decode(p[from:i])))
+ from = i + 1
+ }
+ }
+ return r
+}
diff --git a/libgo/go/syscall/errno.c b/libgo/go/syscall/errno.c
index 854b5aaec28..8e57811151a 100644
--- a/libgo/go/syscall/errno.c
+++ b/libgo/go/syscall/errno.c
@@ -5,21 +5,22 @@
license that can be found in the LICENSE file. */
#include <errno.h>
+#include <stdint.h>
/* errno is typically a macro. These functions set
and get errno specific to the libc being used. */
-int GetErrno() asm ("libgo_syscall.syscall.GetErrno");
-void SetErrno(int) asm ("libgo_syscall.syscall.SetErrno");
+uintptr_t GetErrno() asm ("libgo_syscall.syscall.GetErrno");
+void SetErrno(uintptr_t) asm ("libgo_syscall.syscall.SetErrno");
-int
+uintptr_t
GetErrno()
{
- return errno;
+ return (uintptr_t) errno;
}
void
-SetErrno(int value)
+SetErrno(uintptr_t value)
{
- errno = value;
+ errno = (int) value;
}
diff --git a/libgo/go/syscall/errstr.go b/libgo/go/syscall/errstr.go
index d9f3fe82eb4..5ef10da1fd4 100644
--- a/libgo/go/syscall/errstr.go
+++ b/libgo/go/syscall/errstr.go
@@ -6,14 +6,14 @@
package syscall
-//sysnb strerror_r(errnum int, buf []byte) (errno int)
+//sysnb strerror_r(errnum int, buf []byte) (err error)
//strerror_r(errnum int, buf *byte, buflen Size_t) int
func Errstr(errnum int) string {
for len := 128; ; len *= 2 {
b := make([]byte, len)
err := strerror_r(errnum, b)
- if err == 0 {
+ if err == nil {
i := 0
for b[i] != 0 {
i++
diff --git a/libgo/go/syscall/exec_stubs.go b/libgo/go/syscall/exec_stubs.go
index 02b9ec34cf3..74b0af597e8 100644
--- a/libgo/go/syscall/exec_stubs.go
+++ b/libgo/go/syscall/exec_stubs.go
@@ -14,10 +14,10 @@ func Exec(argv0 string, argv []string, envv []string) (err int) {
return ENOSYS;
}
-func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, errno int) {
+func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, err error) {
return -1, ENOSYS;
}
-func raw_ptrace(request int, pid int, addr *byte, data *byte) int {
+func raw_ptrace(request int, pid int, addr *byte, data *byte) Errno {
return ENOSYS
}
diff --git a/libgo/go/syscall/exec_unix.go b/libgo/go/syscall/exec_unix.go
index 60e9770ce23..c9814b7050e 100644
--- a/libgo/go/syscall/exec_unix.go
+++ b/libgo/go/syscall/exec_unix.go
@@ -11,39 +11,43 @@ import (
"unsafe"
)
-//sysnb raw_fork() (pid Pid_t, errno int)
+//sysnb raw_fork() (pid Pid_t, err Errno)
//fork() Pid_t
-//sysnb raw_setsid() (errno int)
+//sysnb raw_setsid() (err Errno)
//setsid() Pid_t
-//sysnb raw_chroot(path *byte) (errno int)
+//sysnb raw_setpgid(pid int, pgid int) (err Errno)
+//setpgid(pid Pid_t, pgid Pid_t) int
+
+//sysnb raw_chroot(path *byte) (err Errno)
//chroot(path *byte) int
-//sysnb raw_chdir(path *byte) (errno int)
+//sysnb raw_chdir(path *byte) (err Errno)
//chdir(path *byte) int
-//sysnb raw_fcntl(fd int, cmd int, arg int) (val int, errno int)
+//sysnb raw_fcntl(fd int, cmd int, arg int) (val int, err Errno)
//fcntl(fd int, cmd int, arg int) int
-//sysnb raw_close(fd int) (errno int)
+//sysnb raw_close(fd int) (err Errno)
//close(fd int) int
-//sysnb raw_ioctl(fd int, cmd int, val int) (rval int, errno int)
+//sysnb raw_ioctl(fd int, cmd int, val int) (rval int, err Errno)
//ioctl(fd int, cmd int, val int) int
-//sysnb raw_execve(argv0 *byte, argv **byte, envv **byte) (errno int)
+//sysnb raw_execve(argv0 *byte, argv **byte, envv **byte) (err Errno)
//execve(argv0 *byte, argv **byte, envv **byte) int
-//sysnb raw_read(fd int, p *byte, np int) (n int, errno int)
-//read(fd int, buf *byte, count Size_t) Ssize_t
-
-//sysnb raw_write(fd int, buf *byte, count int) int
+//sysnb raw_write(fd int, buf *byte, count int) (err Errno)
//write(fd int, buf *byte, count Size_t) Ssize_t
//sysnb raw_exit(status int)
//_exit(status int)
+// Note: not raw, returns error rather than Errno.
+//sys read(fd int, p *byte, np int) (n int, err error)
+//read(fd int, buf *byte, count Size_t) Ssize_t
+
// Lock synchronizing creation of new file descriptors with fork.
//
// We want the child in a fork/exec sequence to inherit only the
@@ -106,9 +110,9 @@ func StringSlicePtr(ss []string) []*byte {
func CloseOnExec(fd int) { fcntl(fd, F_SETFD, FD_CLOEXEC) }
-func SetNonblock(fd int, nonblocking bool) (errno int) {
+func SetNonblock(fd int, nonblocking bool) (err error) {
flag, err := fcntl(fd, F_GETFL, 0)
- if err != 0 {
+ if err != nil {
return err
}
if nonblocking {
@@ -121,20 +125,22 @@ func SetNonblock(fd int, nonblocking bool) (errno int) {
}
// Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child.
-// If a dup or exec fails, write the errno int to pipe.
+// If a dup or exec fails, write the errno error to pipe.
// (Pipe is close-on-exec so if exec succeeds, it will be closed.)
// In the child, this function must not acquire any locks, because
// they might have been locked at the time of the fork. This means
// no rescheduling, no malloc calls, and no new stack segments.
// The calls to RawSyscall are okay because they are assembly
// functions that do not grow the stack.
-func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err int) {
+func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) {
// Declare all variables at top in case any
// declarations require heap allocation (e.g., err1).
- var r1 Pid_t
- var err1 int
- var nextfd int
- var i int
+ var (
+ r1 Pid_t
+ err1 Errno
+ nextfd int
+ i int
+ )
// guard against side effects of shuffling fds below.
fd := append([]int(nil), attr.Files...)
@@ -143,7 +149,7 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
// No more allocation or calls of non-assembly functions.
r1, err1 = raw_fork()
if err1 != 0 {
- return 0, int(err1)
+ return 0, err1
}
if r1 != 0 {
@@ -171,7 +177,7 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
// Set process group
if sys.Setpgid {
- err1 = Setpgid(0, 0)
+ err1 = raw_setpgid(0, 0)
if err1 != 0 {
goto childerror
}
@@ -189,23 +195,35 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
if cred := sys.Credential; cred != nil {
ngroups := len(cred.Groups)
if ngroups == 0 {
- err1 = setgroups(0, nil)
+ err2 := setgroups(0, nil)
+ if err2 == nil {
+ err1 = 0
+ } else {
+ err1 = err2.(Errno)
+ }
} else {
groups := make([]Gid_t, ngroups)
for i, v := range cred.Groups {
groups[i] = Gid_t(v)
}
- err1 = setgroups(ngroups, &groups[0])
+ err2 := setgroups(ngroups, &groups[0])
+ if err2 == nil {
+ err1 = 0
+ } else {
+ err1 = err2.(Errno)
+ }
}
if err1 != 0 {
goto childerror
}
- err1 = Setgid(int(cred.Gid))
- if err1 != 0 {
+ err2 := Setgid(int(cred.Gid))
+ if err2 != nil {
+ err1 = err2.(Errno)
goto childerror
}
- err1 = Setuid(int(cred.Uid))
- if err1 != 0 {
+ err2 = Setuid(int(cred.Uid))
+ if err2 != nil {
+ err1 = err2.(Errno)
goto childerror
}
}
@@ -222,8 +240,9 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
// so that pass 2 won't stomp on an fd it needs later.
nextfd = int(len(fd))
if pipe < nextfd {
- _, err1 = Dup2(pipe, nextfd)
- if err1 != 0 {
+ _, err2 := Dup2(pipe, nextfd)
+ if err2 != nil {
+ err1 = err2.(Errno)
goto childerror
}
raw_fcntl(nextfd, F_SETFD, FD_CLOEXEC)
@@ -232,8 +251,9 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
}
for i = 0; i < len(fd); i++ {
if fd[i] >= 0 && fd[i] < int(i) {
- _, err1 = Dup2(fd[i], nextfd)
- if err1 != 0 {
+ _, err2 := Dup2(fd[i], nextfd)
+ if err2 != nil {
+ err1 = err2.(Errno)
goto childerror
}
raw_fcntl(nextfd, F_SETFD, FD_CLOEXEC)
@@ -262,8 +282,9 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
}
// The new fd is created NOT close-on-exec,
// which is exactly what we want.
- _, err1 = Dup2(fd[i], i)
- if err1 != 0 {
+ _, err2 := Dup2(fd[i], i)
+ if err2 != nil {
+ err1 = err2.(Errno)
goto childerror
}
}
@@ -338,10 +359,10 @@ type SysProcAttr struct {
var zeroProcAttr ProcAttr
var zeroSysProcAttr SysProcAttr
-func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) {
+func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
var p [2]int
var n int
- var err1 uintptr
+ var err1 Errno
var wstatus WaitStatus
if attr == nil {
@@ -379,32 +400,32 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) {
ForkLock.Lock()
// Allocate child status pipe close on exec.
- if err = Pipe(p[0:]); err != 0 {
+ if err = Pipe(p[0:]); err != nil {
goto error
}
- if _, err = fcntl(p[0], F_SETFD, FD_CLOEXEC); err != 0 {
+ if _, err = fcntl(p[0], F_SETFD, FD_CLOEXEC); err != nil {
goto error
}
- if _, err = fcntl(p[1], F_SETFD, FD_CLOEXEC); err != 0 {
+ if _, err = fcntl(p[1], F_SETFD, FD_CLOEXEC); err != nil {
goto error
}
// Kick off child.
- pid, err = forkAndExecInChild(argv0p, argvp, envvp, chroot, dir, attr, sys, p[1])
- if err != 0 {
+ pid, err1 = forkAndExecInChild(argv0p, argvp, envvp, chroot, dir, attr, sys, p[1])
+ if err1 != 0 {
goto error
}
ForkLock.Unlock()
// Read child error status from pipe.
Close(p[1])
- n, err = raw_read(p[0], (*byte)(unsafe.Pointer(&err1)), int(unsafe.Sizeof(err1)))
+ n, err = read(p[0], (*byte)(unsafe.Pointer(&err1)), int(unsafe.Sizeof(err1)))
Close(p[0])
- if err != 0 || n != 0 {
+ if err != nil || n != 0 {
if n == int(unsafe.Sizeof(err1)) {
- err = int(err1)
+ err = Errno(err1)
}
- if err == 0 {
+ if err == nil {
err = EPIPE
}
@@ -418,7 +439,7 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) {
}
// Read got EOF, so pipe closed on exec, so exec succeeded.
- return pid, 0
+ return pid, nil
error:
if p[0] >= 0 {
@@ -430,20 +451,20 @@ error:
}
// Combination of fork and exec, careful to be thread safe.
-func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) {
+func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
return forkExec(argv0, argv, attr)
}
// StartProcess wraps ForkExec for package os.
-func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid, handle int, err int) {
+func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid, handle int, err error) {
pid, err = forkExec(argv0, argv, attr)
return pid, 0, err
}
// Ordinary exec.
-func Exec(argv0 string, argv []string, envv []string) (err int) {
+func Exec(argv0 string, argv []string, envv []string) (err error) {
err1 := raw_execve(StringBytePtr(argv0),
&StringSlicePtr(argv)[0],
&StringSlicePtr(envv)[0])
- return int(err1)
+ return Errno(err1)
}
diff --git a/libgo/go/syscall/exec_windows.go b/libgo/go/syscall/exec_windows.go
index e8b540ad160..2826e2f35a6 100644
--- a/libgo/go/syscall/exec_windows.go
+++ b/libgo/go/syscall/exec_windows.go
@@ -8,8 +8,8 @@ package syscall
import (
"sync"
+ "unicode/utf16"
"unsafe"
- "utf16"
)
var ForkLock sync.RWMutex
@@ -100,7 +100,7 @@ func makeCmdLine(args []string) string {
// Last bytes are two UCS-2 NULs, or four NUL bytes.
func createEnvBlock(envv []string) *uint16 {
if len(envv) == 0 {
- return &utf16.Encode([]int("\x00\x00"))[0]
+ return &utf16.Encode([]rune("\x00\x00"))[0]
}
length := 0
for _, s := range envv {
@@ -118,54 +118,54 @@ func createEnvBlock(envv []string) *uint16 {
}
copy(b[i:i+1], []byte{0})
- return &utf16.Encode([]int(string(b)))[0]
+ return &utf16.Encode([]rune(string(b)))[0]
}
func CloseOnExec(fd Handle) {
SetHandleInformation(Handle(fd), HANDLE_FLAG_INHERIT, 0)
}
-func SetNonblock(fd Handle, nonblocking bool) (errno int) {
- return 0
+func SetNonblock(fd Handle, nonblocking bool) (err error) {
+ return nil
}
// getFullPath retrieves the full path of the specified file.
// Just a wrapper for Windows GetFullPathName api.
-func getFullPath(name string) (path string, err int) {
+func getFullPath(name string) (path string, err error) {
p := StringToUTF16Ptr(name)
buf := make([]uint16, 100)
n, err := GetFullPathName(p, uint32(len(buf)), &buf[0], nil)
- if err != 0 {
+ if err != nil {
return "", err
}
if n > uint32(len(buf)) {
// Windows is asking for bigger buffer.
buf = make([]uint16, n)
n, err = GetFullPathName(p, uint32(len(buf)), &buf[0], nil)
- if err != 0 {
+ if err != nil {
return "", err
}
if n > uint32(len(buf)) {
return "", EINVAL
}
}
- return UTF16ToString(buf[:n]), 0
+ return UTF16ToString(buf[:n]), nil
}
func isSlash(c uint8) bool {
return c == '\\' || c == '/'
}
-func normalizeDir(dir string) (name string, err int) {
+func normalizeDir(dir string) (name string, err error) {
ndir, err := getFullPath(dir)
- if err != 0 {
+ if err != nil {
return "", err
}
if len(ndir) > 2 && isSlash(ndir[0]) && isSlash(ndir[1]) {
// dir cannot have \\server\share\path form
return "", EINVAL
}
- return ndir, 0
+ return ndir, nil
}
func volToUpper(ch int) int {
@@ -175,13 +175,13 @@ func volToUpper(ch int) int {
return ch
}
-func joinExeDirAndFName(dir, p string) (name string, err int) {
+func joinExeDirAndFName(dir, p string) (name string, err error) {
if len(p) == 0 {
return "", EINVAL
}
if len(p) > 2 && isSlash(p[0]) && isSlash(p[1]) {
// \\server\share\path form
- return p, 0
+ return p, nil
}
if len(p) > 1 && p[1] == ':' {
// has drive letter
@@ -189,10 +189,10 @@ func joinExeDirAndFName(dir, p string) (name string, err int) {
return "", EINVAL
}
if isSlash(p[2]) {
- return p, 0
+ return p, nil
} else {
d, err := normalizeDir(dir)
- if err != 0 {
+ if err != nil {
return "", err
}
if volToUpper(int(p[0])) == volToUpper(int(d[0])) {
@@ -204,7 +204,7 @@ func joinExeDirAndFName(dir, p string) (name string, err int) {
} else {
// no drive letter
d, err := normalizeDir(dir)
- if err != 0 {
+ if err != nil {
return "", err
}
if isSlash(p[0]) {
@@ -232,7 +232,7 @@ type SysProcAttr struct {
var zeroProcAttr ProcAttr
var zeroSysProcAttr SysProcAttr
-func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid, handle int, err int) {
+func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid, handle int, err error) {
if len(argv0) == 0 {
return 0, 0, EWINDOWS
}
@@ -255,9 +255,9 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid, handle int,
// argv0 relative to the current directory, and, only once the new
// process is started, it does Chdir(attr.Dir). We are adjusting
// for that difference here by making argv0 absolute.
- var err int
+ var err error
argv0, err = joinExeDirAndFName(attr.Dir, argv0)
- if err != 0 {
+ if err != nil {
return 0, 0, err
}
}
@@ -294,7 +294,7 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid, handle int,
for i := range attr.Files {
if attr.Files[i] > 0 {
err := DuplicateHandle(p, Handle(attr.Files[i]), p, &fd[i], 0, true, DUPLICATE_SAME_ACCESS)
- if err != 0 {
+ if err != nil {
return 0, 0, err
}
defer CloseHandle(Handle(fd[i]))
@@ -314,14 +314,14 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid, handle int,
pi := new(ProcessInformation)
err = CreateProcess(argv0p, argvp, nil, nil, true, CREATE_UNICODE_ENVIRONMENT, createEnvBlock(attr.Env), dirp, si, pi)
- if err != 0 {
+ if err != nil {
return 0, 0, err
}
defer CloseHandle(Handle(pi.Thread))
- return int(pi.ProcessId), int(pi.Process), 0
+ return int(pi.ProcessId), int(pi.Process), nil
}
-func Exec(argv0 string, argv []string, envv []string) (err int) {
+func Exec(argv0 string, argv []string, envv []string) (err error) {
return EWINDOWS
}
diff --git a/libgo/go/syscall/libcall_irix.go b/libgo/go/syscall/libcall_irix.go
index ae453559713..69e0db264bd 100644
--- a/libgo/go/syscall/libcall_irix.go
+++ b/libgo/go/syscall/libcall_irix.go
@@ -4,5 +4,5 @@
package syscall
-//sysnb raw_ptrace(request int, pid int, addr *byte, data *byte) (errno int)
+//sysnb raw_ptrace(request int, pid int, addr *byte, data *byte) (err Errno)
//ptrace(request int, pid Pid_t, addr *byte, data *byte) _C_long
diff --git a/libgo/go/syscall/libcall_linux.go b/libgo/go/syscall/libcall_linux.go
index 3948e51ae28..79f5d48ae8b 100644
--- a/libgo/go/syscall/libcall_linux.go
+++ b/libgo/go/syscall/libcall_linux.go
@@ -8,31 +8,31 @@ package syscall
import "unsafe"
-//sys Openat(dirfd int, path string, flags int, mode uint32) (fd int, errno int)
+//sys Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
//openat(dirfd int, path *byte, flags int, mode Mode_t) int
-//sys futimesat(dirfd int, path *byte, times *[2]Timeval) (errno int)
+//sys futimesat(dirfd int, path *byte, times *[2]Timeval) (err error)
//futimesat(dirfd int, path *byte, times *[2]Timeval) int
-func Futimesat(dirfd int, path string, tv []Timeval) (errno int) {
+func Futimesat(dirfd int, path string, tv []Timeval) (err error) {
if len(tv) != 2 {
return EINVAL
}
return futimesat(dirfd, StringBytePtr(path), (*[2]Timeval)(unsafe.Pointer(&tv[0])))
}
-func Futimes(fd int, tv []Timeval) (errno int) {
+func Futimes(fd int, tv []Timeval) (err error) {
// Believe it or not, this is the best we can do on GNU/Linux
// (and is what glibc does).
return Utimes("/proc/self/fd/"+itoa(fd), tv)
}
-//sys ptrace(request int, pid int, addr uintptr, data uintptr) (errno int)
+//sys ptrace(request int, pid int, addr uintptr, data uintptr) (err error)
//ptrace(request int, pid Pid_t, addr *byte, data *byte) _C_long
-//sysnb raw_ptrace(request int, pid int, addr *byte, data *byte) (errno int)
+//sysnb raw_ptrace(request int, pid int, addr *byte, data *byte) (err Errno)
//ptrace(request int, pid Pid_t, addr *byte, data *byte) _C_long
-func ptracePeek(req int, pid int, addr uintptr, out []byte) (count int, errno int) {
+func ptracePeek(req int, pid int, addr uintptr, out []byte) (count int, err error) {
// The peek requests are machine-size oriented, so we wrap it
// to retrieve arbitrary-length data.
@@ -48,9 +48,9 @@ func ptracePeek(req int, pid int, addr uintptr, out []byte) (count int, errno in
// boundary.
n := 0
if addr%sizeofPtr != 0 {
- errno = ptrace(req, pid, addr-addr%sizeofPtr, uintptr(unsafe.Pointer(&buf[0])))
- if errno != 0 {
- return 0, errno
+ err = ptrace(req, pid, addr-addr%sizeofPtr, uintptr(unsafe.Pointer(&buf[0])))
+ if err != nil {
+ return 0, err
}
n += copy(out, buf[addr%sizeofPtr:])
out = out[n:]
@@ -60,27 +60,27 @@ func ptracePeek(req int, pid int, addr uintptr, out []byte) (count int, errno in
for len(out) > 0 {
// We use an internal buffer to gaurantee alignment.
// It's not documented if this is necessary, but we're paranoid.
- errno = ptrace(req, pid, addr+uintptr(n), uintptr(unsafe.Pointer(&buf[0])))
- if errno != 0 {
- return n, errno
+ err = ptrace(req, pid, addr+uintptr(n), uintptr(unsafe.Pointer(&buf[0])))
+ if err != nil {
+ return n, err
}
copied := copy(out, buf[0:])
n += copied
out = out[copied:]
}
- return n, 0
+ return n, nil
}
-func PtracePeekText(pid int, addr uintptr, out []byte) (count int, errno int) {
+func PtracePeekText(pid int, addr uintptr, out []byte) (count int, err error) {
return ptracePeek(PTRACE_PEEKTEXT, pid, addr, out)
}
-func PtracePeekData(pid int, addr uintptr, out []byte) (count int, errno int) {
+func PtracePeekData(pid int, addr uintptr, out []byte) (count int, err error) {
return ptracePeek(PTRACE_PEEKDATA, pid, addr, out)
}
-func ptracePoke(pokeReq int, peekReq int, pid int, addr uintptr, data []byte) (count int, errno int) {
+func ptracePoke(pokeReq int, peekReq int, pid int, addr uintptr, data []byte) (count int, err error) {
// As for ptracePeek, we need to align our accesses to deal
// with the possibility of straddling an invalid page.
@@ -88,15 +88,15 @@ func ptracePoke(pokeReq int, peekReq int, pid int, addr uintptr, data []byte) (c
n := 0
if addr%sizeofPtr != 0 {
var buf [sizeofPtr]byte
- errno = ptrace(peekReq, pid, addr-addr%sizeofPtr, uintptr(unsafe.Pointer(&buf[0])))
- if errno != 0 {
- return 0, errno
+ err = ptrace(peekReq, pid, addr-addr%sizeofPtr, uintptr(unsafe.Pointer(&buf[0])))
+ if err != nil {
+ return 0, err
}
n += copy(buf[addr%sizeofPtr:], data)
word := *((*uintptr)(unsafe.Pointer(&buf[0])))
- errno = ptrace(pokeReq, pid, addr-addr%sizeofPtr, word)
- if errno != 0 {
- return 0, errno
+ err = ptrace(pokeReq, pid, addr-addr%sizeofPtr, word)
+ if err != nil {
+ return 0, err
}
data = data[n:]
}
@@ -104,9 +104,9 @@ func ptracePoke(pokeReq int, peekReq int, pid int, addr uintptr, data []byte) (c
// Interior.
for len(data) > int(sizeofPtr) {
word := *((*uintptr)(unsafe.Pointer(&data[0])))
- errno = ptrace(pokeReq, pid, addr+uintptr(n), word)
- if errno != 0 {
- return n, errno
+ err = ptrace(pokeReq, pid, addr+uintptr(n), word)
+ if err != nil {
+ return n, err
}
n += int(sizeofPtr)
data = data[sizeofPtr:]
@@ -115,167 +115,167 @@ func ptracePoke(pokeReq int, peekReq int, pid int, addr uintptr, data []byte) (c
// Trailing edge.
if len(data) > 0 {
var buf [sizeofPtr]byte
- errno = ptrace(peekReq, pid, addr+uintptr(n), uintptr(unsafe.Pointer(&buf[0])))
- if errno != 0 {
- return n, errno
+ err = ptrace(peekReq, pid, addr+uintptr(n), uintptr(unsafe.Pointer(&buf[0])))
+ if err != nil {
+ return n, err
}
copy(buf[0:], data)
word := *((*uintptr)(unsafe.Pointer(&buf[0])))
- errno = ptrace(pokeReq, pid, addr+uintptr(n), word)
- if errno != 0 {
- return n, errno
+ err = ptrace(pokeReq, pid, addr+uintptr(n), word)
+ if err != nil {
+ return n, err
}
n += len(data)
}
- return n, 0
+ return n, nil
}
-func PtracePokeText(pid int, addr uintptr, data []byte) (count int, errno int) {
+func PtracePokeText(pid int, addr uintptr, data []byte) (count int, err error) {
return ptracePoke(PTRACE_POKETEXT, PTRACE_PEEKTEXT, pid, addr, data)
}
-func PtracePokeData(pid int, addr uintptr, data []byte) (count int, errno int) {
+func PtracePokeData(pid int, addr uintptr, data []byte) (count int, err error) {
return ptracePoke(PTRACE_POKEDATA, PTRACE_PEEKDATA, pid, addr, data)
}
-func PtraceGetRegs(pid int, regsout *PtraceRegs) (errno int) {
+func PtraceGetRegs(pid int, regsout *PtraceRegs) (err error) {
return ptrace(PTRACE_GETREGS, pid, 0, uintptr(unsafe.Pointer(regsout)))
}
-func PtraceSetRegs(pid int, regs *PtraceRegs) (errno int) {
+func PtraceSetRegs(pid int, regs *PtraceRegs) (err error) {
return ptrace(PTRACE_SETREGS, pid, 0, uintptr(unsafe.Pointer(regs)))
}
-func PtraceSetOptions(pid int, options int) (errno int) {
+func PtraceSetOptions(pid int, options int) (err error) {
return ptrace(PTRACE_SETOPTIONS, pid, 0, uintptr(options))
}
-func PtraceGetEventMsg(pid int) (msg uint, errno int) {
+func PtraceGetEventMsg(pid int) (msg uint, err error) {
var data _C_long
- errno = ptrace(PTRACE_GETEVENTMSG, pid, 0, uintptr(unsafe.Pointer(&data)))
+ err = ptrace(PTRACE_GETEVENTMSG, pid, 0, uintptr(unsafe.Pointer(&data)))
msg = uint(data)
return
}
-func PtraceCont(pid int, signal int) (errno int) {
+func PtraceCont(pid int, signal int) (err error) {
return ptrace(PTRACE_CONT, pid, 0, uintptr(signal))
}
-func PtraceSingleStep(pid int) (errno int) { return ptrace(PTRACE_SINGLESTEP, pid, 0, 0) }
+func PtraceSingleStep(pid int) (err error) { return ptrace(PTRACE_SINGLESTEP, pid, 0, 0) }
-func PtraceAttach(pid int) (errno int) { return ptrace(PTRACE_ATTACH, pid, 0, 0) }
+func PtraceAttach(pid int) (err error) { return ptrace(PTRACE_ATTACH, pid, 0, 0) }
-func PtraceDetach(pid int) (errno int) { return ptrace(PTRACE_DETACH, pid, 0, 0) }
+func PtraceDetach(pid int) (err error) { return ptrace(PTRACE_DETACH, pid, 0, 0) }
// FIXME: mksysinfo needs to produce LINUX_REBOOT_MAGIC[12].
-// //sys reboot(magic1 uint, magic2 uint, cmd int, arg string) (errno int)
+// //sys reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error)
// //reboot(magic1 uint, magic2 uint, cmd int, arg *byte) int
-// func Reboot(cmd int) (errno int) {
+// func Reboot(cmd int) (err error) {
// return reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, "")
// }
-//sys Acct(path string) (errno int)
+//sys Acct(path string) (err error)
//acct(path *byte) int
// FIXME: mksysinfo Timex
-// //sys Adjtimex(buf *Timex) (state int, errno int)
+// //sys Adjtimex(buf *Timex) (state int, err error)
// //adjtimex(buf *Timex) int
-//sys Faccessat(dirfd int, path string, mode uint32, flags int) (errno int)
+//sys Faccessat(dirfd int, path string, mode uint32, flags int) (err error)
//faccessat(dirfd int, pathname *byte, mode int, flags int) int
// FIXME: Only in glibc 2.10 and later.
-// //sys Fallocate(fd int, mode uint32, off int64, len int64) (errno int)
+// //sys Fallocate(fd int, mode uint32, off int64, len int64) (err error)
// //fallocate(fd int, mode int, offset Offset_t, len Offset_t) int
-//sys Fchmodat(dirfd int, path string, mode uint32, flags int) (errno int)
+//sys Fchmodat(dirfd int, path string, mode uint32, flags int) (err error)
//fchmodat(dirfd int, pathname *byte, mode Mode_t, flags int) int
-//sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (errno int)
+//sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error)
//fchownat(dirfd int, path *byte, owner Uid_t, group Gid_t, flags int) int
-//sys Flock(fd int, how int) (errno int)
+//sys Flock(fd int, how int) (err error)
//flock(fd int, how int) int
// FIXME: mksysinfo statfs
-// //sys Fstatfs(fd int, buf *Statfs_t) (errno int)
+// //sys Fstatfs(fd int, buf *Statfs_t) (err error)
// //fstatfs(fd int, buf *Statfs_t) int
// FIXME: Only available as a syscall.
// //sysnb Gettid() (tid int)
// //gettid() Pid_t
-//sys Ioperm(from int, num int, on int) (errno int)
+//sys Ioperm(from int, num int, on int) (err error)
//ioperm(from _C_long, num _C_long, on int) int
-//sys Iopl(level int) (errno int)
+//sys Iopl(level int) (err error)
//iopl(level int) int
// FIXME: mksysinfo linux_dirent
// Or just abandon this function.
-// //sys Getdents(fd int, buf []byte) (n int, errno int)
+// //sys Getdents(fd int, buf []byte) (n int, err error)
// //getdents64(fd int, buf *byte, count uint)
-//sys InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, errno int)
+//sys InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err error)
//inotify_add_watch(fd int, pathname *byte, mask uint32) int
-//sysnb InotifyInit() (fd int, errno int)
+//sysnb InotifyInit() (fd int, err error)
//inotify_init() int
// FIXME: Only in glibc 2.9 and later.
-// //sysnb InotifyInit1(flags int) (fd int, errno int)
+// //sysnb InotifyInit1(flags int) (fd int, err error)
// //inotify_init1(flags int) int
-//sysnb InotifyRmWatch(fd int, watchdesc uint32) (success int, errno int)
+//sysnb InotifyRmWatch(fd int, watchdesc uint32) (success int, err error)
//inotify_rm_watch(fd int, wd uint32) int
-//sys Klogctl(typ int, buf []byte) (n int, errno int)
+//sys Klogctl(typ int, buf []byte) (n int, err error)
//klogctl(typ int, bufp *byte, len int) int
-//sys Mkdirat(dirfd int, path string, mode uint32) (errno int)
+//sys Mkdirat(dirfd int, path string, mode uint32) (err error)
//mkdirat(dirfd int, path *byte, mode Mode_t) int
-//sys Mknodat(dirfd int, path string, mode uint32, dev int) (errno int)
+//sys Mknodat(dirfd int, path string, mode uint32, dev int) (err error)
//mknodat(dirfd int, path *byte, mode Mode_t, dev _dev_t) int
-//sys PivotRoot(newroot string, putold string) (errno int)
+//sys PivotRoot(newroot string, putold string) (err error)
//pivot_root(newroot *byte, putold *byte) int
-//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (errno int)
+//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error)
//renameat(olddirfd int, oldpath *byte, newdirfd int, newpath *byte) int
-//sys sendfile(outfd int, infd int, offset *Offset_t, count int) (written int, errno int)
+//sys sendfile(outfd int, infd int, offset *Offset_t, count int) (written int, err error)
//sendfile64(outfd int, infd int, offset *Offset_t, count Size_t) Ssize_t
-func Sendfile(outfd int, infd int, offset *int64, count int) (written int, errno int) {
+func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
var soff Offset_t
var psoff *Offset_t
if offset != nil {
psoff = &soff
}
- written, errno = sendfile(outfd, infd, psoff, count)
+ written, err = sendfile(outfd, infd, psoff, count)
if offset != nil {
*offset = int64(soff)
}
return
}
-//sys Setfsgid(gid int) (errno int)
+//sys Setfsgid(gid int) (err error)
//setfsgid(gid Gid_t) int
-//sys Setfsuid(uid int) (errno int)
+//sys Setfsuid(uid int) (err error)
//setfsuid(uid Uid_t) int
-//sysnb Setresgid(rgid int, egid int, sgid int) (errno int)
+//sysnb Setresgid(rgid int, egid int, sgid int) (err error)
//setresgid(rgid Gid_t, egid Gid_t, sgid Gid_t) int
-//sysnb Setresuid(ruid int, eguid int, suid int) (errno int)
+//sysnb Setresuid(ruid int, eguid int, suid int) (err error)
//setresuid(ruid Uid_t, euid Uid_t, suid Uid_t) int
-//sys splice(rfd int, roff *_loff_t, wfd int, woff *_loff_t, len int, flags int) (n int64, errno int)
+//sys splice(rfd int, roff *_loff_t, wfd int, woff *_loff_t, len int, flags int) (n int64, err error)
//splice(rfd int, roff *_loff_t, wfd int, woff *_loff_t, len Size_t, flags uint) Ssize_t
-func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, errno int) {
+func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error) {
var lroff _loff_t
var plroff *_loff_t
if (roff != nil) {
@@ -286,7 +286,7 @@ func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n i
if (woff != nil) {
plwoff = &lwoff
}
- n, errno = splice(rfd, plroff, wfd, plwoff, len, flags)
+ n, err = splice(rfd, plroff, wfd, plwoff, len, flags)
if (roff != nil) {
*roff = int64(lroff)
}
@@ -297,37 +297,37 @@ func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n i
}
// FIXME: mksysinfo statfs
-// //sys Statfs(path string, buf *Statfs_t) (errno int)
+// //sys Statfs(path string, buf *Statfs_t) (err error)
// //statfs(path *byte, buf *Statfs_t) int
// FIXME: Only in glibc 2.6 and later.
-// //sys SyncFileRange(fd int, off int64, n int64, flags int) (errno int)
+// //sys SyncFileRange(fd int, off int64, n int64, flags int) (err error)
// //sync_file_range(fd int, off Offset_t, n Offset_t, flags uint) int
// FIXME: mksysinfo Sysinfo_t
-// //sysnb Sysinfo(info *Sysinfo_t) (errno int)
+// //sysnb Sysinfo(info *Sysinfo_t) (err error)
// //sysinfo(info *Sysinfo_t) int
-//sys Tee(rfd int, wfd int, len int, flags int) (n int64, errno int)
+//sys Tee(rfd int, wfd int, len int, flags int) (n int64, err error)
//tee(rfd int, wfd int, len Size_t, flags uint) Ssize_t
// FIXME: Only available as a syscall.
-// //sysnb Tgkill(tgid int, tid int, sig int) (errno int)
+// //sysnb Tgkill(tgid int, tid int, sig int) (err error)
// //tgkill(tgid int, tid int, sig int) int
-//sys unlinkat(dirfd int, path string, flags int) (errno int)
+//sys unlinkat(dirfd int, path string, flags int) (err error)
//unlinkat(dirfd int, path *byte, flags int) int
-func Unlinkat(dirfd int, path string) (errno int) {
+func Unlinkat(dirfd int, path string) (err error) {
return unlinkat(dirfd, path, 0)
}
-//sys Unmount(target string, flags int) (errno int) = SYS_UMOUNT2
+//sys Unmount(target string, flags int) (err error) = SYS_UMOUNT2
//umount2(target *byte, flags int) int
-//sys Unshare(flags int) (errno int)
+//sys Unshare(flags int) (err error)
//unshare(flags int) int
// FIXME: mksysinfo Ustat_t
-// //sys Ustat(dev int, ubuf *Ustat_t) (errno int)
+// //sys Ustat(dev int, ubuf *Ustat_t) (err error)
// //ustat(dev _dev_t, ubuf *Ustat_t) int
diff --git a/libgo/go/syscall/libcall_posix.go b/libgo/go/syscall/libcall_posix.go
index 87ed4e628fd..d90e595dba3 100644
--- a/libgo/go/syscall/libcall_posix.go
+++ b/libgo/go/syscall/libcall_posix.go
@@ -17,43 +17,43 @@ import "unsafe"
* Wrapped
*/
-//sysnb pipe(p *[2]int) (errno int)
+//sysnb pipe(p *[2]int) (err error)
//pipe(p *[2]int) int
-func Pipe(p []int) (errno int) {
+func Pipe(p []int) (err error) {
if len(p) != 2 {
return EINVAL
}
var pp [2]int
- errno = pipe(&pp)
+ err = pipe(&pp)
p[0] = pp[0]
p[1] = pp[1]
return
}
-//sys utimes(path string, times *[2]Timeval) (errno int)
+//sys utimes(path string, times *[2]Timeval) (err error)
//utimes(path *byte, times *[2]Timeval) int
-func Utimes(path string, tv []Timeval) (errno int) {
+func Utimes(path string, tv []Timeval) (err error) {
if len(tv) != 2 {
return EINVAL
}
return utimes(path, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
}
-//sys getcwd(buf *byte, size Size_t) (errno int)
+//sys getcwd(buf *byte, size Size_t) (err error)
//getcwd(buf *byte, size Size_t) *byte
const ImplementsGetwd = true
-func Getwd() (ret string, errno int) {
+func Getwd() (ret string, err error) {
for len := Size_t(4096); ; len *= 2 {
b := make([]byte, len)
err := getcwd(&b[0], len)
- if err == 0 {
- i := 0;
+ if err == nil {
+ i := 0
for b[i] != 0 {
- i++;
+ i++
}
- return string(b[0:i]), 0;
+ return string(b[0:i]), nil
}
if err != ERANGE {
return "", err
@@ -61,16 +61,16 @@ func Getwd() (ret string, errno int) {
}
}
-//sysnb getgroups(size int, list *Gid_t) (nn int, errno int)
+//sysnb getgroups(size int, list *Gid_t) (nn int, err error)
//getgroups(size int, list *Gid_t) int
-func Getgroups() (gids []int, errno int) {
+func Getgroups() (gids []int, err error) {
n, err := getgroups(0, nil)
- if err != 0 {
- return nil, errno
+ if err != nil {
+ return nil, err
}
if n == 0 {
- return nil, 0
+ return nil, nil
}
// Sanity check group count. Max is 1<<16 on GNU/Linux.
@@ -80,8 +80,8 @@ func Getgroups() (gids []int, errno int) {
a := make([]Gid_t, n)
n, err = getgroups(n, &a[0])
- if err != 0 {
- return nil, errno
+ if err != nil {
+ return nil, err
}
gids = make([]int, n)
for i, v := range a[0:n] {
@@ -90,10 +90,10 @@ func Getgroups() (gids []int, errno int) {
return
}
-//sysnb setgroups(n int, list *Gid_t) (errno int)
+//sysnb setgroups(n int, list *Gid_t) (err error)
//setgroups(n Size_t, list *Gid_t) int
-func Setgroups(gids []int) (errno int) {
+func Setgroups(gids []int) (err error) {
if len(gids) == 0 {
return setgroups(0, nil)
}
@@ -120,10 +120,10 @@ func (w WaitStatus) Signal() int
func (w WaitStatus) StopSignal() int
func (w WaitStatus) TrapCause() int
-//sys Mkfifo(path string, mode uint32) (errno int)
+//sys Mkfifo(path string, mode uint32) (err error)
//mkfifo(path *byte, mode Mode_t) int
-//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, errno int)
+//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error)
//select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) int
const nfdbits = unsafe.Sizeof(fds_bits_type) * 8
@@ -154,52 +154,52 @@ func FDZero(set *FdSet) {
}
}
-//sys Access(path string, mode uint32) (errno int)
+//sys Access(path string, mode uint32) (err error)
//access(path *byte, mode int) int
-//sys Chdir(path string) (errno int)
+//sys Chdir(path string) (err error)
//chdir(path *byte) int
-//sys Chmod(path string, mode uint32) (errno int)
+//sys Chmod(path string, mode uint32) (err error)
//chmod(path *byte, mode Mode_t) int
-//sys Chown(path string, uid int, gid int) (errno int)
+//sys Chown(path string, uid int, gid int) (err error)
//chown(path *byte, uid Uid_t, gid Gid_t) int
-//sys Chroot(path string) (errno int)
+//sys Chroot(path string) (err error)
//chroot(path *byte) int
-//sys Close(fd int) (errno int)
+//sys Close(fd int) (err error)
//close(fd int) int
-//sys Creat(path string, mode uint32) (fd int, errno int)
+//sys Creat(path string, mode uint32) (fd int, err error)
//creat(path *byte, mode Mode_t) int
-//sysnb Dup(oldfd int) (fd int, errno int)
+//sysnb Dup(oldfd int) (fd int, err error)
//dup(oldfd int) int
-//sysnb Dup2(oldfd int, newfd int) (fd int, errno int)
+//sysnb Dup2(oldfd int, newfd int) (fd int, err error)
//dup2(oldfd int, newfd int) int
//sys Exit(code int)
//exit(code int)
-//sys Fchdir(fd int) (errno int)
+//sys Fchdir(fd int) (err error)
//fchdir(fd int) int
-//sys Fchmod(fd int, mode uint32) (errno int)
+//sys Fchmod(fd int, mode uint32) (err error)
//fchmod(fd int, mode Mode_t) int
-//sys Fchown(fd int, uid int, gid int) (errno int)
+//sys Fchown(fd int, uid int, gid int) (err error)
//fchown(fd int, uid Uid_t, gid Gid_t) int
-//sys fcntl(fd int, cmd int, arg int) (val int, errno int)
+//sys fcntl(fd int, cmd int, arg int) (val int, err error)
//fcntl(fd int, cmd int, arg int) int
-//sys Fdatasync(fd int) (errno int)
+//sys Fdatasync(fd int) (err error)
//fdatasync(fd int) int
-//sys Fsync(fd int) (errno int)
+//sys Fsync(fd int) (err error)
//fsync(fd int) int
//sysnb Getegid() (egid int)
@@ -214,7 +214,7 @@ func FDZero(set *FdSet) {
//sysnb Getpagesize() (pagesize int)
//getpagesize() int
-//sysnb Getpgid(pid int) (pgid int, errno int)
+//sysnb Getpgid(pid int) (pgid int, err error)
//getpgid(pid Pid_t) Pid_t
//sysnb Getpgrp() (pid int)
@@ -227,138 +227,138 @@ func FDZero(set *FdSet) {
//getppid() Pid_t
// FIXME: mksysinfo Rlimit
-// //sysnb Getrlimit(resource int, rlim *Rlimit) (errno int)
+// //sysnb Getrlimit(resource int, rlim *Rlimit) (err error)
// //getrlimit(resource int, rlim *Rlimit) int
-//sysnb Getrusage(who int, rusage *Rusage) (errno int)
+//sysnb Getrusage(who int, rusage *Rusage) (err error)
//getrusage(who int, rusage *Rusage) int
-//sysnb gettimeofday(tv *Timeval, tz *byte) (errno int)
+//sysnb gettimeofday(tv *Timeval, tz *byte) (err error)
//gettimeofday(tv *Timeval, tz *byte) int
-func Gettimeofday(tv *Timeval) (errno int) {
+func Gettimeofday(tv *Timeval) (err error) {
return gettimeofday(tv, nil)
}
//sysnb Getuid() (uid int)
//getuid() Uid_t
-//sysnb Kill(pid int, sig int) (errno int)
+//sysnb Kill(pid int, sig int) (err error)
//kill(pid Pid_t, sig int) int
-//sys Lchown(path string, uid int, gid int) (errno int)
+//sys Lchown(path string, uid int, gid int) (err error)
//lchown(path *byte, uid Uid_t, gid Gid_t) int
-//sys Link(oldpath string, newpath string) (errno int)
+//sys Link(oldpath string, newpath string) (err error)
//link(oldpath *byte, newpath *byte) int
-//sys Mkdir(path string, mode uint32) (errno int)
+//sys Mkdir(path string, mode uint32) (err error)
//mkdir(path *byte, mode Mode_t) int
-//sys Mknod(path string, mode uint32, dev int) (errno int)
+//sys Mknod(path string, mode uint32, dev int) (err error)
//mknod(path *byte, mode Mode_t, dev _dev_t) int
-//sys Mount(source string, target string, fstype string, flags int, data string) (errno int)
+//sys Mount(source string, target string, fstype string, flags int, data string) (err error)
//mount(source *byte, target *byte, fstype *byte, flags _C_long, data *byte) int
-//sys Nanosleep(time *Timespec, leftover *Timespec) (errno int)
+//sys Nanosleep(time *Timespec, leftover *Timespec) (err error)
//nanosleep(time *Timespec, leftover *Timespec) int
-//sys Pause() (errno int)
+//sys Pause() (err error)
//pause() int
-//sys Read(fd int, p []byte) (n int, errno int)
+//sys Read(fd int, p []byte) (n int, err error)
//read(fd int, buf *byte, count Size_t) Ssize_t
-//sys Readlink(path string, buf []byte) (n int, errno int)
+//sys Readlink(path string, buf []byte) (n int, err error)
//readlink(path *byte, buf *byte, bufsiz Size_t) Ssize_t
-//sys Rename(oldpath string, newpath string) (errno int)
+//sys Rename(oldpath string, newpath string) (err error)
//rename(oldpath *byte, newpath *byte) int
-//sys Rmdir(path string) (errno int)
+//sys Rmdir(path string) (err error)
//rmdir(path *byte) int
-//sys Setdomainname(p []byte) (errno int)
+//sys Setdomainname(p []byte) (err error)
//setdomainname(name *byte, len Size_t) int
-//sys Sethostname(p []byte) (errno int)
+//sys Sethostname(p []byte) (err error)
//sethostname(name *byte, len Size_t) int
-//sysnb Setgid(gid int) (errno int)
+//sysnb Setgid(gid int) (err error)
//setgid(gid Gid_t) int
-//sysnb Setregid(rgid int, egid int) (errno int)
+//sysnb Setregid(rgid int, egid int) (err error)
//setregid(rgid Gid_t, egid Gid_t) int
-//sysnb Setpgid(pid int, pgid int) (errno int)
+//sysnb Setpgid(pid int, pgid int) (err error)
//setpgid(pid Pid_t, pgid Pid_t) int
-//sysnb Setreuid(ruid int, euid int) (errno int)
+//sysnb Setreuid(ruid int, euid int) (err error)
//setreuid(ruid Uid_t, euid Uid_t) int
// FIXME: mksysinfo Rlimit
-// //sysnb Setrlimit(resource int, rlim *Rlimit) (errno int)
+// //sysnb Setrlimit(resource int, rlim *Rlimit) (err error)
// //setrlimit(resource int, rlim *Rlimit) int
-//sysnb Setsid() (pid int, errno int)
+//sysnb Setsid() (pid int, err error)
//setsid() Pid_t
-//sysnb settimeofday(tv *Timeval, tz *byte) (errno int)
+//sysnb settimeofday(tv *Timeval, tz *byte) (err error)
//settimeofday(tv *Timeval, tz *byte) int
-func Settimeofday(tv *Timeval) (errno int) {
+func Settimeofday(tv *Timeval) (err error) {
return settimeofday(tv, nil)
}
-//sysnb Setuid(uid int) (errno int)
+//sysnb Setuid(uid int) (err error)
//setuid(uid Uid_t) int
-//sys Symlink(oldpath string, newpath string) (errno int)
+//sys Symlink(oldpath string, newpath string) (err error)
//symlink(oldpath *byte, newpath *byte) int
//sys Sync()
//sync()
// FIXME: mksysinfo Time_t
-// //sysnb Time(t *Time_t) (tt Time_t, errno int)
+// //sysnb Time(t *Time_t) (tt Time_t, err error)
// //time(t *Time_t) Time_t
// FIXME: mksysinfo Tms
-// //sysnb Times(tms *Tms) (ticks uintptr, errno int)
+// //sysnb Times(tms *Tms) (ticks uintptr, err error)
// //times(tms *Tms) _clock_t
//sysnb Umask(mask int) (oldmask int)
//umask(mask Mode_t) Mode_t
-//sys Unlink(path string) (errno int)
+//sys Unlink(path string) (err error)
//unlink(path *byte) int
// FIXME: mksysinfo Utimbuf
-// //sys Utime(path string, buf *Utimbuf) (errno int)
+// //sys Utime(path string, buf *Utimbuf) (err error)
// //utime(path *byte, buf *Utimbuf) int
-//sys Write(fd int, p []byte) (n int, errno int)
+//sys Write(fd int, p []byte) (n int, err error)
//write(fd int, buf *byte, count Size_t) Ssize_t
-//sys munmap(addr uintptr, length uintptr) (errno int)
+//sys munmap(addr uintptr, length uintptr) (err error)
//munmap(addr *byte, length Size_t) int
-//sys Madvise(b []byte, advice int) (errno int)
+//sys Madvise(b []byte, advice int) (err error)
//madvise(addr *byte, len Size_t, advice int) int
-//sys Mprotect(b []byte, prot int) (errno int)
+//sys Mprotect(b []byte, prot int) (err error)
//mprotect(addr *byte, len Size_t, prot int) int
-//sys Mlock(b []byte) (errno int)
+//sys Mlock(b []byte) (err error)
//mlock(addr *byte, len Size_t) int
-//sys Munlock(b []byte) (errno int)
+//sys Munlock(b []byte) (err error)
//munlock(addr *byte, len Size_t) int
-//sys Mlockall(flags int) (errno int)
+//sys Mlockall(flags int) (err error)
//mlockall(flags int) int
-//sys Munlockall() (errno int)
+//sys Munlockall() (err error)
//munlockall() int
func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
@@ -378,8 +378,8 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
return
}
-//sysnb Tcgetattr(fd int, p *Termios) (errno int)
+//sysnb Tcgetattr(fd int, p *Termios) (err error)
//tcgetattr(fd int, p *Termios) int
-//sys Tcsetattr(fd int, actions int, p *Termios) (errno int)
+//sys Tcsetattr(fd int, actions int, p *Termios) (err error)
//tcsetattr(fd int, actions int, p *Termios) int
diff --git a/libgo/go/syscall/libcall_posix_largefile.go b/libgo/go/syscall/libcall_posix_largefile.go
index acfafecc581..e898648157d 100644
--- a/libgo/go/syscall/libcall_posix_largefile.go
+++ b/libgo/go/syscall/libcall_posix_largefile.go
@@ -6,32 +6,32 @@
package syscall
-//sys Fstat(fd int, stat *Stat_t) (errno int)
+//sys Fstat(fd int, stat *Stat_t) (err error)
//fstat64(fd int, stat *Stat_t) int
-//sys Ftruncate(fd int, length int64) (errno int)
+//sys Ftruncate(fd int, length int64) (err error)
//ftruncate64(fd int, length Offset_t) int
-//sys Lstat(path string, stat *Stat_t) (errno int)
+//sys Lstat(path string, stat *Stat_t) (err error)
//lstat64(path *byte, stat *Stat_t) int
-//sys mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, errno int)
+//sys mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error)
//mmap64(addr *byte, length Size_t, prot int, flags int, fd int, offset Offset_t) *byte
-//sys Open(path string, mode int, perm uint32) (fd int, errno int)
+//sys Open(path string, mode int, perm uint32) (fd int, err error)
//open64(path *byte, mode int, perm Mode_t) int
-//sys Pread(fd int, p []byte, offset int64) (n int, errno int)
+//sys Pread(fd int, p []byte, offset int64) (n int, err error)
//pread64(fd int, buf *byte, count Size_t, offset Offset_t) Ssize_t
-//sys Pwrite(fd int, p []byte, offset int64) (n int, errno int)
+//sys Pwrite(fd int, p []byte, offset int64) (n int, err error)
//pwrite64(fd int, buf *byte, count Size_t, offset Offset_t) Ssize_t
-//sys Seek(fd int, offset int64, whence int) (off int64, errno int)
+//sys Seek(fd int, offset int64, whence int) (off int64, err error)
//lseek64(fd int, offset Offset_t, whence int) Offset_t
-//sys Stat(path string, stat *Stat_t) (errno int)
+//sys Stat(path string, stat *Stat_t) (err error)
//stat64(path *byte, stat *Stat_t) int
-//sys Truncate(path string, length int64) (errno int)
+//sys Truncate(path string, length int64) (err error)
//truncate64(path *byte, length Offset_t) int
diff --git a/libgo/go/syscall/libcall_posix_regfile.go b/libgo/go/syscall/libcall_posix_regfile.go
index b71da0ceb48..97167013a18 100644
--- a/libgo/go/syscall/libcall_posix_regfile.go
+++ b/libgo/go/syscall/libcall_posix_regfile.go
@@ -7,32 +7,32 @@
package syscall
-//sys Fstat(fd int, stat *Stat_t) (errno int)
+//sys Fstat(fd int, stat *Stat_t) (err error)
//fstat(fd int, stat *Stat_t) int
-//sys Ftruncate(fd int, length int64) (errno int)
+//sys Ftruncate(fd int, length int64) (err error)
//ftruncate(fd int, length Offset_t) int
-//sys Lstat(path string, stat *Stat_t) (errno int)
+//sys Lstat(path string, stat *Stat_t) (err error)
//lstat(path *byte, stat *Stat_t) int
-//sys mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, errno int)
+//sys mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error)
//mmap(addr *byte, length Size_t, prot int, flags int, fd int, offset Offset_t) *byte
-//sys Open(path string, mode int, perm uint32) (fd int, errno int)
+//sys Open(path string, mode int, perm uint32) (fd int, err error)
//open(path *byte, mode int, perm Mode_t) int
-//sys Pread(fd int, p []byte, offset int64) (n int, errno int)
+//sys Pread(fd int, p []byte, offset int64) (n int, err error)
//pread(fd int, buf *byte, count Size_t, offset Offset_t) Ssize_t
-//sys Pwrite(fd int, p []byte, offset int64) (n int, errno int)
+//sys Pwrite(fd int, p []byte, offset int64) (n int, err error)
//pwrite(fd int, buf *byte, count Size_t, offset Offset_t) Ssize_t
-//sys Seek(fd int, offset int64, whence int) (off int64, errno int)
+//sys Seek(fd int, offset int64, whence int) (off int64, err error)
//lseek(fd int, offset Offset_t, whence int) Offset_t
-//sys Stat(path string, stat *Stat_t) (errno int)
+//sys Stat(path string, stat *Stat_t) (err error)
//stat(path *byte, stat *Stat_t) int
-//sys Truncate(path string, length int64) (errno int)
+//sys Truncate(path string, length int64) (err error)
//truncate(path *byte, length Offset_t) int
diff --git a/libgo/go/syscall/libcall_solaris_386.go b/libgo/go/syscall/libcall_solaris_386.go
index 9c4e966f1ae..e94deecf8cd 100644
--- a/libgo/go/syscall/libcall_solaris_386.go
+++ b/libgo/go/syscall/libcall_solaris_386.go
@@ -5,8 +5,8 @@
package syscall
// 32-bit Solaris 2/x86 needs to use _nuname internally, cf. <sys/utsname.h>.
-//sysnb Uname(buf *Utsname) (errno int)
+//sysnb Uname(buf *Utsname) (err error)
//_nuname(buf *Utsname) int
-//sysnb raw_ptrace(request int, pid int, addr *byte, data *byte) (errno int)
+//sysnb raw_ptrace(request int, pid int, addr *byte, data *byte) (err Errno)
//ptrace(request int, pid Pid_t, addr *byte, data *byte) _C_long
diff --git a/libgo/go/syscall/libcall_solaris_amd64.go b/libgo/go/syscall/libcall_solaris_amd64.go
index f0d335dbb67..69b11ba5ee6 100644
--- a/libgo/go/syscall/libcall_solaris_amd64.go
+++ b/libgo/go/syscall/libcall_solaris_amd64.go
@@ -5,6 +5,6 @@
package syscall
// 64-bit ptrace(3C) doesn't exist
-func raw_ptrace(request int, pid int, addr *byte, data *byte) int {
+func raw_ptrace(request int, pid int, addr *byte, data *byte) Errno {
return ENOSYS
}
diff --git a/libgo/go/syscall/libcall_solaris_sparc.go b/libgo/go/syscall/libcall_solaris_sparc.go
index ae453559713..69e0db264bd 100644
--- a/libgo/go/syscall/libcall_solaris_sparc.go
+++ b/libgo/go/syscall/libcall_solaris_sparc.go
@@ -4,5 +4,5 @@
package syscall
-//sysnb raw_ptrace(request int, pid int, addr *byte, data *byte) (errno int)
+//sysnb raw_ptrace(request int, pid int, addr *byte, data *byte) (err Errno)
//ptrace(request int, pid Pid_t, addr *byte, data *byte) _C_long
diff --git a/libgo/go/syscall/libcall_solaris_sparc64.go b/libgo/go/syscall/libcall_solaris_sparc64.go
index f0d335dbb67..69b11ba5ee6 100644
--- a/libgo/go/syscall/libcall_solaris_sparc64.go
+++ b/libgo/go/syscall/libcall_solaris_sparc64.go
@@ -5,6 +5,6 @@
package syscall
// 64-bit ptrace(3C) doesn't exist
-func raw_ptrace(request int, pid int, addr *byte, data *byte) int {
+func raw_ptrace(request int, pid int, addr *byte, data *byte) Errno {
return ENOSYS
}
diff --git a/libgo/go/syscall/libcall_support.go b/libgo/go/syscall/libcall_support.go
index daed8073caf..7449a0adf79 100644
--- a/libgo/go/syscall/libcall_support.go
+++ b/libgo/go/syscall/libcall_support.go
@@ -8,5 +8,5 @@ package syscall
func entersyscall()
func exitsyscall()
-func GetErrno() int
-func SetErrno(int)
+func GetErrno() Errno
+func SetErrno(Errno)
diff --git a/libgo/go/syscall/libcall_uname.go b/libgo/go/syscall/libcall_uname.go
index e4c32b12d6a..519e6dc25d0 100644
--- a/libgo/go/syscall/libcall_uname.go
+++ b/libgo/go/syscall/libcall_uname.go
@@ -4,5 +4,5 @@
package syscall
-//sysnb Uname(buf *Utsname) (errno int)
+//sysnb Uname(buf *Utsname) (err error)
//uname(buf *Utsname) int
diff --git a/libgo/go/syscall/libcall_wait4.go b/libgo/go/syscall/libcall_wait4.go
index 7a63bc71e97..578686926f3 100644
--- a/libgo/go/syscall/libcall_wait4.go
+++ b/libgo/go/syscall/libcall_wait4.go
@@ -6,14 +6,13 @@
package syscall
-//sys wait4(pid Pid_t, status *int, options int, rusage *Rusage) (wpid Pid_t, errno int)
+//sys wait4(pid Pid_t, status *int, options int, rusage *Rusage) (wpid Pid_t, err error)
//wait4(pid Pid_t, status *int, options int, rusage *Rusage) Pid_t
-func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, errno int) {
+func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, err error) {
var status int
r, err := wait4(Pid_t(pid), &status, options, rusage)
wpid = int(r)
- errno = err
if wstatus != nil {
*wstatus = WaitStatus(status)
}
diff --git a/libgo/go/syscall/libcall_waitpid.go b/libgo/go/syscall/libcall_waitpid.go
index 014446307e3..1c476d829d0 100644
--- a/libgo/go/syscall/libcall_waitpid.go
+++ b/libgo/go/syscall/libcall_waitpid.go
@@ -6,14 +6,13 @@
package syscall
-//sys waitpid(pid Pid_t, status *int, options int) (wpid Pid_t, errno int)
+//sys waitpid(pid Pid_t, status *int, options int) (wpid Pid_t, err error)
//waitpid(pid Pid_t, status *int, options int) Pid_t
-func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, errno int) {
+func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, err error) {
var status int
r, err := waitpid(Pid_t(pid), &status, options)
wpid = int(r)
- errno = err
if wstatus != nil {
*wstatus = WaitStatus(status)
}
diff --git a/libgo/go/syscall/lsf_linux.go b/libgo/go/syscall/lsf_linux.go
index 0976688b9e7..05d653b4aa0 100644
--- a/libgo/go/syscall/lsf_linux.go
+++ b/libgo/go/syscall/lsf_linux.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.
-// GNU/Linux socket filter
+// Linux socket filter
package syscall
@@ -18,10 +18,10 @@ func LsfJump(code, k, jt, jf int) *SockFilter {
return &SockFilter{Code: uint16(code), Jt: uint8(jt), Jf: uint8(jf), K: uint32(k)}
}
-func LsfSocket(ifindex, proto int) (int, int) {
+func LsfSocket(ifindex, proto int) (int, error) {
var lsall SockaddrLinklayer
s, e := Socket(AF_PACKET, SOCK_RAW, proto)
- if e != 0 {
+ if e != nil {
return 0, e
}
p := (*[2]byte)(unsafe.Pointer(&lsall.Protocol))
@@ -29,11 +29,11 @@ func LsfSocket(ifindex, proto int) (int, int) {
p[1] = byte(proto)
lsall.Ifindex = ifindex
e = Bind(s, &lsall)
- if e != 0 {
+ if e != nil {
Close(s)
return 0, e
}
- return s, 0
+ return s, nil
}
type iflags struct {
@@ -41,17 +41,17 @@ type iflags struct {
flags uint16
}
-func SetLsfPromisc(name string, m bool) int {
+func SetLsfPromisc(name string, m bool) error {
s, e := Socket(AF_INET, SOCK_DGRAM, 0)
- if e != 0 {
+ if e != nil {
return e
}
defer Close(s)
var ifl iflags
copy(ifl.name[:], []byte(name))
_, _, ep := Syscall(SYS_IOCTL, uintptr(s), SIOCGIFFLAGS, uintptr(unsafe.Pointer(&ifl)))
- if e := int(ep); e != 0 {
- return e
+ if ep != 0 {
+ return Errno(ep)
}
if m {
ifl.flags |= uint16(IFF_PROMISC)
@@ -59,20 +59,20 @@ func SetLsfPromisc(name string, m bool) int {
ifl.flags &= ^uint16(IFF_PROMISC)
}
_, _, ep = Syscall(SYS_IOCTL, uintptr(s), SIOCSIFFLAGS, uintptr(unsafe.Pointer(&ifl)))
- if e := int(ep); e != 0 {
- return e
+ if ep != 0 {
+ return Errno(ep)
}
- return 0
+ return nil
}
-func AttachLsf(fd int, i []SockFilter) int {
+func AttachLsf(fd int, i []SockFilter) error {
var p SockFprog
p.Len = uint16(len(i))
p.Filter = (*SockFilter)(unsafe.Pointer(&i[0]))
return setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, uintptr(unsafe.Pointer(&p)), unsafe.Sizeof(p))
}
-func DetachLsf(fd int) int {
+func DetachLsf(fd int) error {
var dummy int
return setsockopt(fd, SOL_SOCKET, SO_DETACH_FILTER, uintptr(unsafe.Pointer(&dummy)), unsafe.Sizeof(dummy))
}
diff --git a/libgo/go/syscall/mksyscall.awk b/libgo/go/syscall/mksyscall.awk
index 49828d94ce3..b02989cc323 100644
--- a/libgo/go/syscall/mksyscall.awk
+++ b/libgo/go/syscall/mksyscall.awk
@@ -12,7 +12,7 @@
# This includes return parameters.
# * The parameter lists must give a type for each argument:
# the (x, y, z int) shorthand is not allowed.
-# * If the return parameter is an error number, it must be named errno.
+# * If the return parameter is an error, it must be named err.
# A line beginning with //sysnb is like //sys, except that the
# goroutine will not be suspended during the execution of the library
@@ -217,13 +217,13 @@ BEGIN {
goname = goparam[1]
gotype = goparam[2]
- if (goname == "errno") {
+ if (goname == "err") {
if (cfnresult ~ /^\*/) {
print "\tif _r == nil {"
} else {
print "\tif _r < 0 {"
}
- print "\t\terrno = GetErrno()"
+ print "\t\terr = GetErrno()"
print "\t}"
} else if (gotype == "uintptr" && cfnresult ~ /^\*/) {
printf("\t%s = (%s)(unsafe.Pointer(_r))\n", goname, gotype)
diff --git a/libgo/go/syscall/netlink_linux.go b/libgo/go/syscall/netlink_linux.go
index 4ee78d62f25..8683bb3dacb 100644
--- a/libgo/go/syscall/netlink_linux.go
+++ b/libgo/go/syscall/netlink_linux.go
@@ -63,31 +63,28 @@ func newNetlinkRouteRequest(proto, seq, family int) []byte {
// NetlinkRIB returns routing information base, as known as RIB,
// which consists of network facility information, states and
// parameters.
-func NetlinkRIB(proto, family int) ([]byte, int) {
+func NetlinkRIB(proto, family int) ([]byte, error) {
var (
- s int
- e int
lsanl SockaddrNetlink
- seq int
tab []byte
)
- s, e = Socket(AF_NETLINK, SOCK_RAW, 0)
- if e != 0 {
+ s, e := Socket(AF_NETLINK, SOCK_RAW, 0)
+ if e != nil {
return nil, e
}
defer Close(s)
lsanl.Family = AF_NETLINK
e = Bind(s, &lsanl)
- if e != 0 {
+ if e != nil {
return nil, e
}
- seq++
+ seq := 1
wb := newNetlinkRouteRequest(proto, seq, family)
e = Sendto(s, wb, 0, &lsanl)
- if e != 0 {
+ if e != nil {
return nil, e
}
@@ -100,7 +97,7 @@ func NetlinkRIB(proto, family int) ([]byte, int) {
rb = make([]byte, Getpagesize())
nr, _, e = Recvfrom(s, rb, 0)
- if e != 0 {
+ if e != nil {
return nil, e
}
if nr < NLMSG_HDRLEN {
@@ -111,7 +108,7 @@ func NetlinkRIB(proto, family int) ([]byte, int) {
msgs, _ := ParseNetlinkMessage(rb)
for _, m := range msgs {
- if lsa, e = Getsockname(s); e != 0 {
+ if lsa, e = Getsockname(s); e != nil {
return nil, e
}
switch v := lsa.(type) {
@@ -132,7 +129,7 @@ func NetlinkRIB(proto, family int) ([]byte, int) {
}
done:
- return tab, 0
+ return tab, nil
}
// NetlinkMessage represents the netlink message.
@@ -143,18 +140,18 @@ type NetlinkMessage struct {
// ParseNetlinkMessage parses buf as netlink messages and returns
// the slice containing the NetlinkMessage structs.
-func ParseNetlinkMessage(buf []byte) ([]NetlinkMessage, int) {
+func ParseNetlinkMessage(buf []byte) ([]NetlinkMessage, error) {
var (
h *NlMsghdr
dbuf []byte
dlen int
- e int
+ e error
msgs []NetlinkMessage
)
for len(buf) >= NLMSG_HDRLEN {
h, dbuf, dlen, e = netlinkMessageHeaderAndData(buf)
- if e != 0 {
+ if e != nil {
break
}
m := NetlinkMessage{}
@@ -167,12 +164,12 @@ func ParseNetlinkMessage(buf []byte) ([]NetlinkMessage, int) {
return msgs, e
}
-func netlinkMessageHeaderAndData(buf []byte) (*NlMsghdr, []byte, int, int) {
+func netlinkMessageHeaderAndData(buf []byte) (*NlMsghdr, []byte, int, error) {
h := (*NlMsghdr)(unsafe.Pointer(&buf[0]))
if int(h.Len) < NLMSG_HDRLEN || int(h.Len) > len(buf) {
return nil, nil, 0, EINVAL
}
- return h, buf[NLMSG_HDRLEN:], nlmAlignOf(int(h.Len)), 0
+ return h, buf[NLMSG_HDRLEN:], nlmAlignOf(int(h.Len)), nil
}
// NetlinkRouteAttr represents the netlink route attribute.
@@ -184,13 +181,13 @@ type NetlinkRouteAttr struct {
// ParseNetlinkRouteAttr parses msg's payload as netlink route
// attributes and returns the slice containing the NetlinkRouteAttr
// structs.
-func ParseNetlinkRouteAttr(msg *NetlinkMessage) ([]NetlinkRouteAttr, int) {
+func ParseNetlinkRouteAttr(msg *NetlinkMessage) ([]NetlinkRouteAttr, error) {
var (
buf []byte
a *RtAttr
alen int
vbuf []byte
- e int
+ e error
attrs []NetlinkRouteAttr
)
@@ -207,7 +204,7 @@ func ParseNetlinkRouteAttr(msg *NetlinkMessage) ([]NetlinkRouteAttr, int) {
for len(buf) >= SizeofRtAttr {
a, vbuf, alen, e = netlinkRouteAttrAndValue(buf)
- if e != 0 {
+ if e != nil {
break
}
ra := NetlinkRouteAttr{}
@@ -217,13 +214,13 @@ func ParseNetlinkRouteAttr(msg *NetlinkMessage) ([]NetlinkRouteAttr, int) {
buf = buf[alen:]
}
- return attrs, 0
+ return attrs, nil
}
-func netlinkRouteAttrAndValue(buf []byte) (*RtAttr, []byte, int, int) {
+func netlinkRouteAttrAndValue(buf []byte) (*RtAttr, []byte, int, error) {
h := (*RtAttr)(unsafe.Pointer(&buf[0]))
if int(h.Len) < SizeofRtAttr || int(h.Len) > len(buf) {
return nil, nil, 0, EINVAL
}
- return h, buf[SizeofRtAttr:], rtaAlignOf(int(h.Len)), 0
+ return h, buf[SizeofRtAttr:], rtaAlignOf(int(h.Len)), nil
}
diff --git a/libgo/go/syscall/route_bsd.go b/libgo/go/syscall/route_bsd.go
index f6b124b64e4..bc4c15e950b 100644
--- a/libgo/go/syscall/route_bsd.go
+++ b/libgo/go/syscall/route_bsd.go
@@ -29,29 +29,24 @@ func rsaAlignOf(salen int) int {
// RouteRIB returns routing information base, as known as RIB,
// which consists of network facility information, states and
// parameters.
-func RouteRIB(facility, param int) ([]byte, int) {
- var (
- tab []byte
- e int
- )
-
+func RouteRIB(facility, param int) ([]byte, error) {
mib := []_C_int{CTL_NET, AF_ROUTE, 0, 0, _C_int(facility), _C_int(param)}
// Find size.
n := uintptr(0)
- if e = sysctl(mib, nil, &n, nil, 0); e != 0 {
- return nil, e
+ if err := sysctl(mib, nil, &n, nil, 0); err != nil {
+ return nil, err
}
if n == 0 {
- return nil, 0
+ return nil, nil
}
- tab = make([]byte, n)
- if e = sysctl(mib, &tab[0], &n, nil, 0); e != 0 {
- return nil, e
+ tab := make([]byte, n)
+ if err := sysctl(mib, &tab[0], &n, nil, 0); err != nil {
+ return nil, err
}
- return tab[:n], 0
+ return tab[:n], nil
}
// RoutingMessage represents a routing message.
@@ -91,7 +86,7 @@ func (m *RouteMessage) sockaddr() []Sockaddr {
switch i {
case RTAX_DST, RTAX_GATEWAY:
sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
- if e != 0 {
+ if e != nil {
return nil
}
if i == RTAX_DST {
@@ -134,7 +129,7 @@ func (m *InterfaceMessage) sockaddr() (sas []Sockaddr) {
return nil
}
sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(&m.Data[0])))
- if e != 0 {
+ if e != nil {
return nil
}
return append(sas, sa)
@@ -163,7 +158,7 @@ func (m *InterfaceAddrMessage) sockaddr() (sas []Sockaddr) {
switch i {
case RTAX_IFA:
sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
- if e != 0 {
+ if e != nil {
return nil
}
sas = append(sas, sa)
@@ -178,7 +173,7 @@ func (m *InterfaceAddrMessage) sockaddr() (sas []Sockaddr) {
// ParseRoutingMessage parses buf as routing messages and returns
// the slice containing the RoutingMessage interfaces.
-func ParseRoutingMessage(buf []byte) (msgs []RoutingMessage, errno int) {
+func ParseRoutingMessage(buf []byte) (msgs []RoutingMessage, err error) {
for len(buf) >= anyMessageLen {
any := (*anyMessage)(unsafe.Pointer(&buf[0]))
if any.Version != RTM_VERSION {
@@ -187,11 +182,11 @@ func ParseRoutingMessage(buf []byte) (msgs []RoutingMessage, errno int) {
msgs = append(msgs, any.toRoutingMessage(buf))
buf = buf[any.Msglen:]
}
- return msgs, 0
+ return msgs, nil
}
// ParseRoutingMessage parses msg's payload as raw sockaddrs and
// returns the slice containing the Sockaddr interfaces.
-func ParseRoutingSockaddr(msg RoutingMessage) (sas []Sockaddr, errno int) {
- return append(sas, msg.sockaddr()...), 0
+func ParseRoutingSockaddr(msg RoutingMessage) (sas []Sockaddr, err error) {
+ return append(sas, msg.sockaddr()...), nil
}
diff --git a/libgo/go/syscall/route_darwin.go b/libgo/go/syscall/route_darwin.go
index 9d3a701daba..410e70a138a 100644
--- a/libgo/go/syscall/route_darwin.go
+++ b/libgo/go/syscall/route_darwin.go
@@ -63,7 +63,7 @@ func (m *InterfaceMulticastAddrMessage) sockaddr() (sas []Sockaddr) {
switch i {
case RTAX_IFA:
sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
- if e != 0 {
+ if e != nil {
return nil
}
sas = append(sas, sa)
diff --git a/libgo/go/syscall/route_freebsd.go b/libgo/go/syscall/route_freebsd.go
index 0d61d08b08c..094e17044db 100644
--- a/libgo/go/syscall/route_freebsd.go
+++ b/libgo/go/syscall/route_freebsd.go
@@ -63,7 +63,7 @@ func (m *InterfaceMulticastAddrMessage) sockaddr() (sas []Sockaddr) {
switch i {
case RTAX_IFA:
sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
- if e != 0 {
+ if e != nil {
return nil
}
sas = append(sas, sa)
diff --git a/libgo/go/syscall/sleep_rtems.go b/libgo/go/syscall/sleep_rtems.go
index 8992eb53c3e..9d72203e8ef 100644
--- a/libgo/go/syscall/sleep_rtems.go
+++ b/libgo/go/syscall/sleep_rtems.go
@@ -6,8 +6,8 @@
package syscall
-func Sleep(nsec int64) (errno int) {
+func Sleep(nsec int64) (err error) {
ts := NsecToTimespec(nsec)
- errno = Nanosleep(&ts, nil)
+ err = Nanosleep(&ts, nil)
return
}
diff --git a/libgo/go/syscall/sleep_select.go b/libgo/go/syscall/sleep_select.go
index 3ebaf58f969..533f554da05 100644
--- a/libgo/go/syscall/sleep_select.go
+++ b/libgo/go/syscall/sleep_select.go
@@ -6,8 +6,8 @@
package syscall
-func Sleep(nsec int64) (errno int) {
+func Sleep(nsec int64) (err error) {
tv := NsecToTimeval(nsec);
- _, err := Select(0, nil, nil, nil, &tv);
+ _, err = Select(0, nil, nil, nil, &tv);
return err;
}
diff --git a/libgo/go/syscall/sockcmsg_linux.go b/libgo/go/syscall/sockcmsg_linux.go
index b025ca52101..0b4caa1d055 100644
--- a/libgo/go/syscall/sockcmsg_linux.go
+++ b/libgo/go/syscall/sockcmsg_linux.go
@@ -26,7 +26,7 @@ func UnixCredentials(ucred *Ucred) []byte {
// ParseUnixCredentials decodes a socket control message that contains
// credentials in a Ucred structure. To receive such a message, the
// SO_PASSCRED option must be enabled on the socket.
-func ParseUnixCredentials(msg *SocketControlMessage) (*Ucred, int) {
+func ParseUnixCredentials(msg *SocketControlMessage) (*Ucred, error) {
if msg.Header.Level != SOL_SOCKET {
return nil, EINVAL
}
@@ -34,5 +34,5 @@ func ParseUnixCredentials(msg *SocketControlMessage) (*Ucred, int) {
return nil, EINVAL
}
ucred := *(*Ucred)(unsafe.Pointer(&msg.Data[0]))
- return &ucred, 0
+ return &ucred, nil
}
diff --git a/libgo/go/syscall/sockcmsg_unix.go b/libgo/go/syscall/sockcmsg_unix.go
index c9872aeba31..84c1383d7e2 100644
--- a/libgo/go/syscall/sockcmsg_unix.go
+++ b/libgo/go/syscall/sockcmsg_unix.go
@@ -47,17 +47,17 @@ type SocketControlMessage struct {
Data []byte
}
-func ParseSocketControlMessage(buf []byte) ([]SocketControlMessage, int) {
+func ParseSocketControlMessage(buf []byte) ([]SocketControlMessage, error) {
var (
h *Cmsghdr
dbuf []byte
- e int
+ e error
cmsgs []SocketControlMessage
)
for len(buf) >= CmsgLen(0) {
h, dbuf, e = socketControlMessageHeaderAndData(buf)
- if e != 0 {
+ if e != nil {
break
}
m := SocketControlMessage{}
@@ -70,12 +70,12 @@ func ParseSocketControlMessage(buf []byte) ([]SocketControlMessage, int) {
return cmsgs, e
}
-func socketControlMessageHeaderAndData(buf []byte) (*Cmsghdr, []byte, int) {
+func socketControlMessageHeaderAndData(buf []byte) (*Cmsghdr, []byte, error) {
h := (*Cmsghdr)(unsafe.Pointer(&buf[0]))
if h.Len < SizeofCmsghdr || int(h.Len) > len(buf) {
return nil, nil, EINVAL
}
- return h, buf[cmsgAlignOf(SizeofCmsghdr):], 0
+ return h, buf[cmsgAlignOf(SizeofCmsghdr):], nil
}
// UnixRights encodes a set of open file descriptors into a socket
@@ -99,7 +99,7 @@ func UnixRights(fds ...int) []byte {
// ParseUnixRights decodes a socket control message that contains an
// integer array of open file descriptors from another process.
-func ParseUnixRights(msg *SocketControlMessage) ([]int, int) {
+func ParseUnixRights(msg *SocketControlMessage) ([]int, error) {
if msg.Header.Level != SOL_SOCKET {
return nil, EINVAL
}
@@ -111,5 +111,5 @@ func ParseUnixRights(msg *SocketControlMessage) ([]int, int) {
fds[j] = int(*(*int32)(unsafe.Pointer(&msg.Data[i])))
j++
}
- return fds, 0
+ return fds, nil
}
diff --git a/libgo/go/syscall/socket.go b/libgo/go/syscall/socket.go
index e0218ba359d..005fd843486 100644
--- a/libgo/go/syscall/socket.go
+++ b/libgo/go/syscall/socket.go
@@ -17,7 +17,7 @@ import "unsafe"
var SocketDisableIPv6 bool
type Sockaddr interface {
- sockaddr() (ptr *RawSockaddrAny, len Socklen_t, errno int) // lowercase; only we can define Sockaddrs
+ sockaddr() (ptr *RawSockaddrAny, len Socklen_t, err error) // lowercase; only we can define Sockaddrs
}
type RawSockaddrAny struct {
@@ -33,7 +33,7 @@ type SockaddrInet4 struct {
raw RawSockaddrInet4
}
-func (sa *SockaddrInet4) sockaddr() (*RawSockaddrAny, Socklen_t, int) {
+func (sa *SockaddrInet4) sockaddr() (*RawSockaddrAny, Socklen_t, error) {
if sa.Port < 0 || sa.Port > 0xFFFF {
return nil, 0, EINVAL
}
@@ -45,7 +45,7 @@ func (sa *SockaddrInet4) sockaddr() (*RawSockaddrAny, Socklen_t, int) {
for i := 0; i < len(sa.Addr); i++ {
sa.raw.Addr[i] = sa.Addr[i]
}
- return (*RawSockaddrAny)(unsafe.Pointer(&sa.raw)), n, 0
+ return (*RawSockaddrAny)(unsafe.Pointer(&sa.raw)), n, nil
}
type SockaddrInet6 struct {
@@ -55,7 +55,7 @@ type SockaddrInet6 struct {
raw RawSockaddrInet6
}
-func (sa *SockaddrInet6) sockaddr() (*RawSockaddrAny, Socklen_t, int) {
+func (sa *SockaddrInet6) sockaddr() (*RawSockaddrAny, Socklen_t, error) {
if sa.Port < 0 || sa.Port > 0xFFFF {
return nil, 0, EINVAL
}
@@ -68,7 +68,7 @@ func (sa *SockaddrInet6) sockaddr() (*RawSockaddrAny, Socklen_t, int) {
for i := 0; i < len(sa.Addr); i++ {
sa.raw.Addr[i] = sa.Addr[i]
}
- return (*RawSockaddrAny)(unsafe.Pointer(&sa.raw)), n, 0
+ return (*RawSockaddrAny)(unsafe.Pointer(&sa.raw)), n, nil
}
type SockaddrUnix struct {
@@ -76,7 +76,7 @@ type SockaddrUnix struct {
raw RawSockaddrUnix
}
-func (sa *SockaddrUnix) sockaddr() (*RawSockaddrAny, Socklen_t, int) {
+func (sa *SockaddrUnix) sockaddr() (*RawSockaddrAny, Socklen_t, error) {
name := sa.Name
n := len(name)
if n >= len(sa.raw.Path) || n == 0 {
@@ -92,186 +92,186 @@ func (sa *SockaddrUnix) sockaddr() (*RawSockaddrAny, Socklen_t, int) {
}
// length is family (uint16), name, NUL.
- return (*RawSockaddrAny)(unsafe.Pointer(&sa.raw)), 2 + Socklen_t(n) + 1, 0
+ return (*RawSockaddrAny)(unsafe.Pointer(&sa.raw)), 2 + Socklen_t(n) + 1, nil
}
-func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, int) {
+func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
switch rsa.Addr.Family {
case AF_UNIX:
pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa))
sa := new(SockaddrUnix)
n, err := pp.getLen()
- if err != 0 {
+ if err != nil {
return nil, err
}
- bytes := (*[len(pp.Path)]byte)(unsafe.Pointer(&pp.Path[0]));
- sa.Name = string(bytes[0:n]);
- return sa, 0;
+ bytes := (*[len(pp.Path)]byte)(unsafe.Pointer(&pp.Path[0]))
+ sa.Name = string(bytes[0:n])
+ return sa, nil
case AF_INET:
- pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa));
- sa := new(SockaddrInet4);
- p := (*[2]byte)(unsafe.Pointer(&pp.Port));
- sa.Port = int(p[0])<<8 + int(p[1]);
+ pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa))
+ sa := new(SockaddrInet4)
+ p := (*[2]byte)(unsafe.Pointer(&pp.Port))
+ sa.Port = int(p[0])<<8 + int(p[1])
for i := 0; i < len(sa.Addr); i++ {
- sa.Addr[i] = pp.Addr[i];
+ sa.Addr[i] = pp.Addr[i]
}
- return sa, 0;
+ return sa, nil
case AF_INET6:
- pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa));
- sa := new(SockaddrInet6);
- p := (*[2]byte)(unsafe.Pointer(&pp.Port));
- sa.Port = int(p[0])<<8 + int(p[1]);
+ pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa))
+ sa := new(SockaddrInet6)
+ p := (*[2]byte)(unsafe.Pointer(&pp.Port))
+ sa.Port = int(p[0])<<8 + int(p[1])
for i := 0; i < len(sa.Addr); i++ {
- sa.Addr[i] = pp.Addr[i];
+ sa.Addr[i] = pp.Addr[i]
}
- return sa, 0;
+ return sa, nil
}
return anyToSockaddrOS(rsa)
}
-//sys accept(fd int, sa *RawSockaddrAny, len *Socklen_t) (nfd int, errno int)
+//sys accept(fd int, sa *RawSockaddrAny, len *Socklen_t) (nfd int, err error)
//accept(fd int, sa *RawSockaddrAny, len *Socklen_t) int
-func Accept(fd int) (nfd int, sa Sockaddr, errno int) {
+func Accept(fd int) (nfd int, sa Sockaddr, err error) {
var rsa RawSockaddrAny
var len Socklen_t = SizeofSockaddrAny
- nfd, errno = accept(fd, &rsa, &len)
- if errno != 0 {
+ nfd, err = accept(fd, &rsa, &len)
+ if err != nil {
return
}
- sa, errno = anyToSockaddr(&rsa)
- if errno != 0 {
+ sa, err = anyToSockaddr(&rsa)
+ if err != nil {
Close(nfd)
nfd = 0
}
return
}
-//sysnb getsockname(fd int, sa *RawSockaddrAny, len *Socklen_t) (errno int)
+//sysnb getsockname(fd int, sa *RawSockaddrAny, len *Socklen_t) (err error)
//getsockname(fd int, sa *RawSockaddrAny, len *Socklen_t) int
-func Getsockname(fd int) (sa Sockaddr, errno int) {
+func Getsockname(fd int) (sa Sockaddr, err error) {
var rsa RawSockaddrAny
var len Socklen_t = SizeofSockaddrAny
- if errno = getsockname(fd, &rsa, &len); errno != 0 {
+ if err = getsockname(fd, &rsa, &len); err != nil {
return
}
return anyToSockaddr(&rsa)
}
-//sysnb getpeername(fd int, sa *RawSockaddrAny, len *Socklen_t) (errno int)
+//sysnb getpeername(fd int, sa *RawSockaddrAny, len *Socklen_t) (err error)
//getpeername(fd int, sa *RawSockaddrAny, len *Socklen_t) int
-func Getpeername(fd int) (sa Sockaddr, errno int) {
+func Getpeername(fd int) (sa Sockaddr, err error) {
var rsa RawSockaddrAny
var len Socklen_t = SizeofSockaddrAny
- if getpeername(fd, &rsa, &len); errno != 0 {
+ if err = getpeername(fd, &rsa, &len); err != nil {
return
}
return anyToSockaddr(&rsa)
}
-//sys bind(fd int, sa *RawSockaddrAny, len Socklen_t) (errno int)
+//sys bind(fd int, sa *RawSockaddrAny, len Socklen_t) (err error)
//bind(fd int, sa *RawSockaddrAny, len Socklen_t) int
-func Bind(fd int, sa Sockaddr) (errno int) {
+func Bind(fd int, sa Sockaddr) (err error) {
ptr, n, err := sa.sockaddr()
- if err != 0 {
+ if err != nil {
return err
}
return bind(fd, ptr, n)
}
-//sys connect(s int, addr *RawSockaddrAny, addrlen Socklen_t) (errno int)
+//sys connect(s int, addr *RawSockaddrAny, addrlen Socklen_t) (err error)
//connect(s int, addr *RawSockaddrAny, addrlen Socklen_t) int
-func Connect(fd int, sa Sockaddr) (errno int) {
+func Connect(fd int, sa Sockaddr) (err error) {
ptr, n, err := sa.sockaddr()
- if err != 0 {
+ if err != nil {
return err
}
return connect(fd, ptr, n)
}
-//sysnb socket(domain int, typ int, proto int) (fd int, errno int)
+//sysnb socket(domain int, typ int, proto int) (fd int, err error)
//socket(domain int, typ int, protocol int) int
-func Socket(domain, typ, proto int) (fd, errno int) {
+func Socket(domain, typ, proto int) (fd int, err error) {
if domain == AF_INET6 && SocketDisableIPv6 {
return -1, EAFNOSUPPORT
}
- fd, errno = socket(domain, typ, proto)
+ fd, err = socket(domain, typ, proto)
return
}
-//sysnb socketpair(domain int, typ int, proto int, fd *[2]int) (errno int)
+//sysnb socketpair(domain int, typ int, proto int, fd *[2]int) (err error)
//socketpair(domain int, typ int, protocol int, fd *[2]int) int
-func Socketpair(domain, typ, proto int) (fd [2]int, errno int) {
- errno = socketpair(domain, typ, proto, &fd)
+func Socketpair(domain, typ, proto int) (fd [2]int, err error) {
+ err = socketpair(domain, typ, proto, &fd)
return
}
-//sys getsockopt(s int, level int, name int, val uintptr, vallen *Socklen_t) (errno int)
+//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 GetsockoptInt(fd, level, opt int) (value, errno int) {
+func GetsockoptInt(fd, level, opt int) (value int, err error) {
var n int32
vallen := Socklen_t(4)
- errno = getsockopt(fd, level, opt, (uintptr)(unsafe.Pointer(&n)), &vallen)
- return int(n), errno
+ err = getsockopt(fd, level, opt, (uintptr)(unsafe.Pointer(&n)), &vallen)
+ return int(n), err
}
-func GetsockoptInet4Addr(fd, level, opt int) (value [4]byte, errno int) {
+func GetsockoptInet4Addr(fd, level, opt int) (value [4]byte, err error) {
vallen := Socklen_t(4)
- errno = getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value[0])), &vallen)
- return value, errno
+ err = getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value[0])), &vallen)
+ return value, err
}
-func GetsockoptIPMreq(fd, level, opt int) (*IPMreq, int) {
+func GetsockoptIPMreq(fd, level, opt int) (*IPMreq, error) {
var value IPMreq
vallen := Socklen_t(SizeofIPMreq)
- errno := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
- return &value, errno
+ err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+ return &value, err
}
/* FIXME: mksysinfo needs to support IPMreqn.
-func GetsockoptIPMreqn(fd, level, opt int) (*IPMreqn, int) {
+func GetsockoptIPMreqn(fd, level, opt int) (*IPMreqn, error) {
var value IPMreqn
vallen := Socklen_t(SizeofIPMreqn)
- errno := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
- return &value, errno
+ err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+ return &value, err
}
*/
/* FIXME: mksysinfo needs to support IPv6Mreq.
-func GetsockoptIPv6Mreq(fd, level, opt int) (*IPv6Mreq, int) {
+func GetsockoptIPv6Mreq(fd, level, opt int) (*IPv6Mreq, error) {
var value IPv6Mreq
vallen := Socklen_t(SizeofIPv6Mreq)
- errno := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
- return &value, errno
+ err := getsockopt(fd, level, opt, uintptr(unsafe.Pointer(&value)), &vallen)
+ return &value, err
}
*/
-//sys setsockopt(s int, level int, name int, val *byte, vallen Socklen_t) (errno int)
+//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 SetsockoptInt(fd, level, opt int, value int) (errno int) {
+func SetsockoptInt(fd, level, opt int, value int) (err error) {
var n = int32(value)
return setsockopt(fd, level, opt, (*byte)(unsafe.Pointer(&n)), 4)
}
-func SetsockoptInet4Addr(fd, level, opt int, value [4]byte) (errno int) {
+func SetsockoptInet4Addr(fd, level, opt int, value [4]byte) (err error) {
return setsockopt(fd, level, opt, (*byte)(unsafe.Pointer(&value[0])), 4)
}
-func SetsockoptTimeval(fd, level, opt int, tv *Timeval) (errno int) {
+func SetsockoptTimeval(fd, level, opt int, tv *Timeval) (err error) {
return setsockopt(fd, level, opt, (*byte)(unsafe.Pointer(tv)), Socklen_t(unsafe.Sizeof(*tv)))
}
@@ -280,58 +280,58 @@ type Linger struct {
Linger int32;
}
-func SetsockoptLinger(fd, level, opt int, l *Linger) (errno int) {
+func SetsockoptLinger(fd, level, opt int, l *Linger) (err error) {
return setsockopt(fd, level, opt, (*byte)(unsafe.Pointer(l)), Socklen_t(unsafe.Sizeof(*l)));
}
-func SetsockoptIPMreq(fd, level, opt int, mreq *IPMreq) (errno int) {
+func SetsockoptIPMreq(fd, level, opt int, mreq *IPMreq) (err error) {
return setsockopt(fd, level, opt, (*byte)(unsafe.Pointer(mreq)), Socklen_t(unsafe.Sizeof(*mreq)))
}
/* FIXME: mksysinfo needs to support IMPreqn.
-func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) (errno int) {
+func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) (err error) {
return setsockopt(fd, level, opt, (*byte)(unsafe.Pointer(mreq)), Socklen_t(unsafe.Sizeof(*mreq)))
}
*/
-func SetsockoptIPv6Mreq(fd, level, opt int, mreq *IPv6Mreq) (errno int) {
+func SetsockoptIPv6Mreq(fd, level, opt int, mreq *IPv6Mreq) (err error) {
return setsockopt(fd, level, opt, (*byte)(unsafe.Pointer(mreq)), Socklen_t(unsafe.Sizeof(*mreq)))
}
-func SetsockoptString(fd, level, opt int, s string) (errno int) {
+func SetsockoptString(fd, level, opt int, s string) (err error) {
return setsockopt(fd, level, opt, (*byte)(unsafe.Pointer(&[]byte(s)[0])), Socklen_t(len(s)))
}
-//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *Socklen_t) (n int, errno int)
+//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *Socklen_t) (n int, err error)
//recvfrom(fd int, buf *byte, len Size_t, flags int, from *RawSockaddrAny, fromlen *Socklen_t) Ssize_t
-func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, errno int) {
+func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error) {
var rsa RawSockaddrAny
var len Socklen_t = SizeofSockaddrAny
- if n, errno = recvfrom(fd, p, flags, &rsa, &len); errno != 0 {
+ if n, err = recvfrom(fd, p, flags, &rsa, &len); err != nil {
return
}
- from, errno = anyToSockaddr(&rsa)
+ from, err = anyToSockaddr(&rsa)
return
}
-//sys sendto(s int, buf []byte, flags int, to *RawSockaddrAny, tolen Socklen_t) (errno int)
+//sys sendto(s int, buf []byte, flags int, to *RawSockaddrAny, tolen Socklen_t) (err error)
//sendto(s int, buf *byte, len Size_t, flags int, to *RawSockaddrAny, tolen Socklen_t) Ssize_t
-func Sendto(fd int, p []byte, flags int, to Sockaddr) (errno int) {
+func Sendto(fd int, p []byte, flags int, to Sockaddr) (err error) {
ptr, n, err := to.sockaddr()
- if err != 0 {
+ if err != nil {
return err
}
return sendto(fd, p, flags, ptr, n)
}
-//sys recvmsg(s int, msg *Msghdr, flags int) (n int, errno int)
+//sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error)
//recvmsg(s int, msg *Msghdr, flags int) Ssize_t
-func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, errno int) {
+func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) {
var msg Msghdr
var rsa RawSockaddrAny
msg.Name = (*byte)(unsafe.Pointer(&rsa))
@@ -353,28 +353,28 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from
}
msg.Iov = &iov
msg.Iovlen = 1
- if n, errno = recvmsg(fd, &msg, flags); errno != 0 {
+ if n, err = recvmsg(fd, &msg, flags); err != nil {
return
}
oobn = int(msg.Controllen)
recvflags = int(msg.Flags)
// source address is only specified if the socket is unconnected
if rsa.Addr.Family != AF_UNSPEC {
- from, errno = anyToSockaddr(&rsa)
+ from, err = anyToSockaddr(&rsa)
}
return
}
-//sys sendmsg(s int, msg *Msghdr, flags int) (errno int)
+//sys sendmsg(s int, msg *Msghdr, flags int) (err error)
//sendmsg(s int, msg *Msghdr, flags int) Ssize_t
-func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (errno int) {
+func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) {
var ptr *RawSockaddrAny
var salen Socklen_t
if to != nil {
- var err int
+ var err error
ptr, salen, err = to.sockaddr()
- if err != 0 {
+ if err != nil {
return err
}
}
@@ -398,16 +398,16 @@ func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (errno int) {
}
msg.Iov = &iov
msg.Iovlen = 1
- if errno = sendmsg(fd, &msg, flags); errno != 0 {
+ if err = sendmsg(fd, &msg, flags); err != nil {
return
}
return
}
-//sys Listen(fd int, n int) (errno int)
+//sys Listen(fd int, n int) (err error)
//listen(fd int, n int) int
-//sys Shutdown(fd int, how int) (errno int)
+//sys Shutdown(fd int, how int) (err error)
//shutdown(fd int, how int) int
func (iov *Iovec) SetLen(length int) {
diff --git a/libgo/go/syscall/socket_bsd.go b/libgo/go/syscall/socket_bsd.go
index 735baf98684..be559915951 100644
--- a/libgo/go/syscall/socket_bsd.go
+++ b/libgo/go/syscall/socket_bsd.go
@@ -47,7 +47,7 @@ func (sa *RawSockaddrUnix) setLen(n int) {
sa.Len = uint8(3 + n) // 2 for Family, Len; 1 for NUL.
}
-func (sa *RawSockaddrUnix) getLen() (int, int) {
+func (sa *RawSockaddrUnix) getLen() (int, error) {
if sa.Len < 3 || sa.Len > SizeofSockaddrUnix {
return 0, EINVAL
}
@@ -59,7 +59,7 @@ func (sa *RawSockaddrUnix) getLen() (int, int) {
break
}
}
- return n, 0
+ return n, nil
}
type RawSockaddr struct {
@@ -69,10 +69,10 @@ type RawSockaddr struct {
}
// BindToDevice binds the socket associated with fd to device.
-func BindToDevice(fd int, device string) (errno int) {
+func BindToDevice(fd int, device string) (err error) {
return ENOSYS
}
-func anyToSockaddrOS(rsa *RawSockaddrAny) (Sockaddr, int) {
- return nil, EAFNOSUPPORT;
+func anyToSockaddrOS(rsa *RawSockaddrAny) (Sockaddr, error) {
+ return nil, EAFNOSUPPORT
}
diff --git a/libgo/go/syscall/socket_irix.go b/libgo/go/syscall/socket_irix.go
index 8bd55b8b4d9..c1fdc656ab0 100644
--- a/libgo/go/syscall/socket_irix.go
+++ b/libgo/go/syscall/socket_irix.go
@@ -41,7 +41,7 @@ type RawSockaddrUnix struct {
func (sa *RawSockaddrUnix) setLen(int) {
}
-func (sa *RawSockaddrUnix) getLen() (int, int) {
+func (sa *RawSockaddrUnix) getLen() (int, error) {
if sa.Path[0] == 0 {
// "Abstract" Unix domain socket.
// Rewrite leading NUL as @ for textual display.
@@ -61,7 +61,7 @@ func (sa *RawSockaddrUnix) getLen() (int, int) {
n++
}
- return n, 0
+ return n, nil
}
type RawSockaddr struct {
@@ -70,7 +70,7 @@ type RawSockaddr struct {
}
// BindToDevice binds the socket associated with fd to device.
-func BindToDevice(fd int, device string) (errno int) {
+func BindToDevice(fd int, device string) (err error) {
return ENOSYS
}
@@ -124,6 +124,6 @@ const (
EAI_MAX = 14
)
-func anyToSockaddrOS(rsa *RawSockaddrAny) (Sockaddr, int) {
- return nil, EAFNOSUPPORT;
+func anyToSockaddrOS(rsa *RawSockaddrAny) (Sockaddr, error) {
+ return nil, EAFNOSUPPORT
}
diff --git a/libgo/go/syscall/socket_linux.go b/libgo/go/syscall/socket_linux.go
index 49aac87bb7a..212e0b2d418 100644
--- a/libgo/go/syscall/socket_linux.go
+++ b/libgo/go/syscall/socket_linux.go
@@ -24,7 +24,7 @@ type SockaddrLinklayer struct {
raw RawSockaddrLinklayer
}
-func (sa *SockaddrLinklayer) sockaddr() (*RawSockaddrAny, Socklen_t, int) {
+func (sa *SockaddrLinklayer) sockaddr() (*RawSockaddrAny, Socklen_t, error) {
if sa.Ifindex < 0 || sa.Ifindex > 0x7fffffff {
return nil, 0, EINVAL
}
@@ -37,7 +37,7 @@ func (sa *SockaddrLinklayer) sockaddr() (*RawSockaddrAny, Socklen_t, int) {
for i := 0; i < len(sa.Addr); i++ {
sa.raw.Addr[i] = sa.Addr[i]
}
- return (*RawSockaddrAny)(unsafe.Pointer(&sa.raw)), SizeofSockaddrLinklayer, 0
+ return (*RawSockaddrAny)(unsafe.Pointer(&sa.raw)), SizeofSockaddrLinklayer, nil
}
type SockaddrNetlink struct {
@@ -48,12 +48,12 @@ type SockaddrNetlink struct {
raw RawSockaddrNetlink
}
-func (sa *SockaddrNetlink) sockaddr() (*RawSockaddrAny, Socklen_t, int) {
+func (sa *SockaddrNetlink) sockaddr() (*RawSockaddrAny, Socklen_t, error) {
sa.raw.Family = AF_NETLINK
sa.raw.Pad = sa.Pad
sa.raw.Pid = sa.Pid
sa.raw.Groups = sa.Groups
- return (*RawSockaddrAny)(unsafe.Pointer(&sa.raw)), SizeofSockaddrNetlink, 0
+ return (*RawSockaddrAny)(unsafe.Pointer(&sa.raw)), SizeofSockaddrNetlink, nil
}
type RawSockaddrInet4 struct {
@@ -87,7 +87,7 @@ type RawSockaddrUnix struct {
func (sa *RawSockaddrUnix) setLen(int) {
}
-func (sa *RawSockaddrUnix) getLen() (int, int) {
+func (sa *RawSockaddrUnix) getLen() (int, error) {
if sa.Path[0] == 0 {
// "Abstract" Unix domain socket.
// Rewrite leading NUL as @ for textual display.
@@ -107,7 +107,7 @@ func (sa *RawSockaddrUnix) getLen() (int, int) {
n++
}
- return n, 0
+ return n, nil
}
type RawSockaddrLinklayer struct {
@@ -133,11 +133,11 @@ type RawSockaddr struct {
}
// BindToDevice binds the socket associated with fd to device.
-func BindToDevice(fd int, device string) (errno int) {
+func BindToDevice(fd int, device string) (err error) {
return SetsockoptString(fd, SOL_SOCKET, SO_BINDTODEVICE, device)
}
-func anyToSockaddrOS(rsa *RawSockaddrAny) (Sockaddr, int) {
+func anyToSockaddrOS(rsa *RawSockaddrAny) (Sockaddr, error) {
switch rsa.Addr.Family {
case AF_NETLINK:
pp := (*RawSockaddrNetlink)(unsafe.Pointer(rsa))
@@ -146,7 +146,7 @@ func anyToSockaddrOS(rsa *RawSockaddrAny) (Sockaddr, int) {
sa.Pad = pp.Pad
sa.Pid = pp.Pid
sa.Groups = pp.Groups
- return sa, 0
+ return sa, nil
case AF_PACKET:
pp := (*RawSockaddrLinklayer)(unsafe.Pointer(rsa))
@@ -159,16 +159,16 @@ func anyToSockaddrOS(rsa *RawSockaddrAny) (Sockaddr, int) {
for i := 0; i < len(sa.Addr); i++ {
sa.Addr[i] = pp.Addr[i]
}
- return sa, 0
+ return sa, nil
}
return nil, EAFNOSUPPORT
}
-//sysnb EpollCreate(size int) (fd int, errno int)
+//sysnb EpollCreate(size int) (fd int, err error)
//epoll_create(size int) int
-//sysnb EpollCtl(epfd int, op int, fd int, event *EpollEvent) (errno int)
+//sysnb EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error)
//epoll_ctl(epfd int, op int, fd int, event *EpollEvent) int
-//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, errno int)
+//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
//epoll_wait(epfd int, events *EpollEvent, maxevents int, timeout int) int
diff --git a/libgo/go/syscall/socket_solaris.go b/libgo/go/syscall/socket_solaris.go
index 0c3e6c9724e..0a03465a338 100644
--- a/libgo/go/syscall/socket_solaris.go
+++ b/libgo/go/syscall/socket_solaris.go
@@ -42,7 +42,7 @@ type RawSockaddrUnix struct {
func (sa *RawSockaddrUnix) setLen(int) {
}
-func (sa *RawSockaddrUnix) getLen() (int, int) {
+func (sa *RawSockaddrUnix) getLen() (int, error) {
if sa.Path[0] == 0 {
// "Abstract" Unix domain socket.
// Rewrite leading NUL as @ for textual display.
@@ -62,7 +62,7 @@ func (sa *RawSockaddrUnix) getLen() (int, int) {
n++
}
- return n, 0
+ return n, nil
}
type RawSockaddr struct {
@@ -71,10 +71,10 @@ type RawSockaddr struct {
}
// BindToDevice binds the socket associated with fd to device.
-func BindToDevice(fd int, device string) (errno int) {
+func BindToDevice(fd int, device string) (err error) {
return ENOSYS
}
-func anyToSockaddrOS(rsa *RawSockaddrAny) (Sockaddr, int) {
- return nil, EAFNOSUPPORT;
+func anyToSockaddrOS(rsa *RawSockaddrAny) (Sockaddr, error) {
+ return nil, EAFNOSUPPORT
}
diff --git a/libgo/go/syscall/syscall.go b/libgo/go/syscall/syscall.go
index a802ba0bbf2..ad9df6cff98 100644
--- a/libgo/go/syscall/syscall.go
+++ b/libgo/go/syscall/syscall.go
@@ -9,8 +9,9 @@
// packages rather than this one if you can.
// For details of the functions and data types in this package consult
// the manuals for the appropriate operating system.
-// These calls return errno == 0 to indicate success; otherwise
-// errno is an operating system error number describing the failure.
+// These calls return err == nil to indicate success; otherwise
+// err is an operating system error describing the failure.
+// On most systems, that error has type syscall.Errno.
package syscall
import "unsafe"
diff --git a/libgo/go/syscall/syscall_unix.go b/libgo/go/syscall/syscall_unix.go
index c734b2cf06a..899a65ca9b4 100644
--- a/libgo/go/syscall/syscall_unix.go
+++ b/libgo/go/syscall/syscall_unix.go
@@ -23,7 +23,7 @@ func c_syscall64(trap int64, a1, a2, a3, a4, a5, a6 int64) int64 __asm__ ("sysca
// Do a system call. We look at the size of uintptr to see how to pass
// the arguments, so that we don't pass a 64-bit value when the function
// expects a 32-bit one.
-func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
+func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) {
entersyscall()
var r uintptr
if unsafe.Sizeof(r) == 4 {
@@ -33,12 +33,12 @@ func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
r1 := c_syscall64(int64(trap), int64(a1), int64(a2), int64(a3), 0, 0, 0)
r = uintptr(r1)
}
- errno := GetErrno()
+ err = GetErrno()
exitsyscall()
- return r, 0, uintptr(errno)
+ return r, 0, err
}
-func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
+func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) {
entersyscall()
var r uintptr
if unsafe.Sizeof(r) == 4 {
@@ -50,12 +50,12 @@ func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
int64(a4), int64(a5), int64(a6))
r = uintptr(r1)
}
- errno := GetErrno()
+ err = GetErrno()
exitsyscall()
- return r, 0, uintptr(errno)
+ return r, 0, err
}
-func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
+func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) {
var r uintptr
if unsafe.Sizeof(r) == 4 {
r1 := c_syscall32(int32(trap), int32(a1), int32(a2), int32(a3), 0, 0, 0)
@@ -64,11 +64,11 @@ func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
r1 := c_syscall64(int64(trap), int64(a1), int64(a2), int64(a3), 0, 0, 0)
r = uintptr(r1)
}
- errno := GetErrno()
- return r, 0, uintptr(errno)
+ err = GetErrno()
+ return r, 0, err
}
-func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
+func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) {
var r uintptr
if unsafe.Sizeof(r) == 4 {
r1 := c_syscall32(int32(trap), int32(a1), int32(a2), int32(a3),
@@ -79,8 +79,8 @@ func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
int64(a4), int64(a5), int64(a6))
r = uintptr(r1)
}
- errno := GetErrno()
- return r, 0, uintptr(errno)
+ err = GetErrno()
+ return r, 0, err
}
// Mmap manager, for use by operating system-specific implementations.
@@ -89,18 +89,18 @@ func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
type mmapper struct {
sync.Mutex
active map[*byte][]byte // active mappings; key is last byte in mapping
- mmap func(addr, length uintptr, prot, flags, fd int, offset int64) (uintptr, int)
- munmap func(addr uintptr, length uintptr) int
+ mmap func(addr, length uintptr, prot, flags, fd int, offset int64) (uintptr, error)
+ munmap func(addr uintptr, length uintptr) error
}
-func (m *mmapper) Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, errno int) {
+func (m *mmapper) Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) {
if length <= 0 {
return nil, EINVAL
}
// Map the requested memory.
addr, errno := m.mmap(0, uintptr(length), prot, flags, fd, offset)
- if errno != 0 {
+ if errno != nil {
return nil, errno
}
@@ -119,10 +119,10 @@ func (m *mmapper) Mmap(fd int, offset int64, length int, prot int, flags int) (d
m.Lock()
defer m.Unlock()
m.active[p] = b
- return b, 0
+ return b, nil
}
-func (m *mmapper) Munmap(data []byte) (errno int) {
+func (m *mmapper) Munmap(data []byte) (err error) {
if len(data) == 0 || len(data) != cap(data) {
return EINVAL
}
@@ -137,11 +137,11 @@ func (m *mmapper) Munmap(data []byte) (errno int) {
}
// Unmap the memory and update m.
- if errno := m.munmap(uintptr(unsafe.Pointer(&b[0])), uintptr(len(b))); errno != 0 {
+ if errno := m.munmap(uintptr(unsafe.Pointer(&b[0])), uintptr(len(b))); errno != nil {
return errno
}
m.active[p] = nil, false
- return 0
+ return nil
}
var mapper = &mmapper{
@@ -150,10 +150,32 @@ var mapper = &mmapper{
munmap: munmap,
}
-func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, errno int) {
+func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) {
return mapper.Mmap(fd, offset, length, prot, flags)
}
-func Munmap(b []byte) (errno int) {
+func Munmap(b []byte) (err error) {
return mapper.Munmap(b)
}
+
+
+// An Errno is an unsigned number describing an error condition.
+// It implements the error interface. The zero Errno is by convention
+// a non-error, so code to convert from Errno to error should use:
+// err = nil
+// if errno != 0 {
+// err = errno
+// }
+type Errno uintptr
+
+func (e Errno) Error() string {
+ return Errstr(int(e))
+}
+
+func (e Errno) Temporary() bool {
+ return e == EINTR || e == EMFILE || e.Timeout()
+}
+
+func (e Errno) Timeout() bool {
+ return e == EAGAIN || e == EWOULDBLOCK || e == ETIMEDOUT
+}
diff --git a/libgo/go/testing/benchmark.go b/libgo/go/testing/benchmark.go
index df4c4a1a29b..4f049a31f75 100644
--- a/libgo/go/testing/benchmark.go
+++ b/libgo/go/testing/benchmark.go
@@ -205,7 +205,7 @@ func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks [
for _, Benchmark := range benchmarks {
matched, err := matchString(*matchBenchmarks, Benchmark.Name)
if err != nil {
- println("invalid regexp for -test.bench:", err.Error())
+ fmt.Fprintf(os.Stderr, "testing: invalid regexp for -test.bench: %s\n", err)
os.Exit(1)
}
if !matched {
@@ -218,11 +218,11 @@ func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks [
if procs != 1 {
benchName = fmt.Sprintf("%s-%d", Benchmark.Name, procs)
}
- print(fmt.Sprintf("%s\t", benchName))
+ fmt.Printf("%s\t", benchName)
r := b.run()
- print(fmt.Sprintf("%v\n", r))
+ fmt.Printf("%v\n", r)
if p := runtime.GOMAXPROCS(-1); p != procs {
- print(fmt.Sprintf("%s left GOMAXPROCS set to %d\n", benchName, p))
+ fmt.Fprintf(os.Stderr, "testing: %s left GOMAXPROCS set to %d\n", benchName, p)
}
}
}
diff --git a/libgo/go/testing/example.go b/libgo/go/testing/example.go
index 5b3e322b593..3b026ee66e0 100644
--- a/libgo/go/testing/example.go
+++ b/libgo/go/testing/example.go
@@ -21,24 +21,23 @@ type InternalExample struct {
func RunExamples(examples []InternalExample) (ok bool) {
ok = true
+ var eg InternalExample
+
stdout, stderr := os.Stdout, os.Stderr
defer func() {
os.Stdout, os.Stderr = stdout, stderr
if e := recover(); e != nil {
- if err, ok := e.(error); ok {
- fmt.Fprintln(os.Stderr, err)
- os.Exit(1)
- }
- panic(e)
+ fmt.Printf("--- FAIL: %s\npanic: %v\n", eg.Name, e)
+ os.Exit(1)
}
}()
- for _, eg := range examples {
+ for _, eg = range examples {
if *chatty {
- fmt.Fprintln(os.Stderr, "=== RUN:", eg.Name)
+ fmt.Printf("=== RUN: %s\n", eg.Name)
}
- // capture stdout and stderr for testing purposes
+ // capture stdout and stderr
r, w, err := os.Pipe()
if err != nil {
fmt.Fprintln(os.Stderr, err)
@@ -50,7 +49,7 @@ func RunExamples(examples []InternalExample) (ok bool) {
buf := new(bytes.Buffer)
_, err := io.Copy(buf, r)
if err != nil {
- fmt.Fprintln(os.Stderr, err)
+ fmt.Fprintf(stderr, "testing: copying pipe: %v\n", err)
os.Exit(1)
}
outC <- buf.String()
@@ -67,16 +66,15 @@ func RunExamples(examples []InternalExample) (ok bool) {
out := <-outC
// report any errors
+ tstr := fmt.Sprintf("(%.2f seconds)", float64(ns)/1e9)
if out != eg.Output {
- fmt.Fprintf(
- os.Stderr,
- "--- FAIL: %s\ngot:\n%s\nwant:\n%s\n",
- eg.Name, out, eg.Output,
+ fmt.Printf(
+ "--- FAIL: %s %s\ngot:\n%s\nwant:\n%s\n",
+ eg.Name, tstr, out, eg.Output,
)
ok = false
} else if *chatty {
- tstr := fmt.Sprintf("(%.2f seconds)", float64(ns)/1e9)
- fmt.Fprintln(os.Stderr, "--- PASS:", eg.Name, tstr)
+ fmt.Printf("--- PASS: %s %s\n", eg.Name, tstr)
}
}
diff --git a/libgo/go/testing/testing.go b/libgo/go/testing/testing.go
index 5869642c7e1..08443a31259 100644
--- a/libgo/go/testing/testing.go
+++ b/libgo/go/testing/testing.go
@@ -75,8 +75,25 @@ func Short() bool {
return *short
}
-// Insert final newline if needed and tabs after internal newlines.
-func tabify(s string) string {
+// decorate inserts the a final newline if needed and indentation tabs for formatting.
+// If addFileLine is true, it also prefixes the string with the file and line of the call site.
+func decorate(s string, addFileLine bool) string {
+ if addFileLine {
+ _, file, line, ok := runtime.Caller(3) // decorate + log + public function.
+ if ok {
+ // Truncate file name at last file name separator.
+ if index := strings.LastIndex(file, "/"); index >= 0 {
+ file = file[index+1:]
+ } else if index = strings.LastIndex(file, "\\"); index >= 0 {
+ file = file[index+1:]
+ }
+ } else {
+ file = "???"
+ line = 1
+ }
+ s = fmt.Sprintf("%s:%d: %s", file, line, s)
+ }
+ s = "\t" + s // Every line is indented at least one tab.
n := len(s)
if n > 0 && s[n-1] != '\n' {
s += "\n"
@@ -84,7 +101,8 @@ func tabify(s string) string {
}
for i := 0; i < n-1; i++ { // -1 to avoid final newline
if s[i] == '\n' {
- return s[0:i+1] + "\t" + tabify(s[i+1:n])
+ // Second and subsequent lines are indented an extra tab.
+ return s[0:i+1] + "\t" + decorate(s[i+1:n], false)
}
}
return s
@@ -116,37 +134,38 @@ func (t *T) FailNow() {
runtime.Goexit()
}
+// log generates the output. It's always at the same stack depth.
+func (t *T) log(s string) { t.errors += decorate(s, true) }
+
// Log formats its arguments using default formatting, analogous to Print(),
// and records the text in the error log.
-func (t *T) Log(args ...interface{}) { t.errors += "\t" + tabify(fmt.Sprintln(args...)) }
+func (t *T) Log(args ...interface{}) { t.log(fmt.Sprintln(args...)) }
// Logf formats its arguments according to the format, analogous to Printf(),
// and records the text in the error log.
-func (t *T) Logf(format string, args ...interface{}) {
- t.errors += "\t" + tabify(fmt.Sprintf(format, args...))
-}
+func (t *T) Logf(format string, args ...interface{}) { t.log(fmt.Sprintf(format, args...)) }
// Error is equivalent to Log() followed by Fail().
func (t *T) Error(args ...interface{}) {
- t.Log(args...)
+ t.log(fmt.Sprintln(args...))
t.Fail()
}
// Errorf is equivalent to Logf() followed by Fail().
func (t *T) Errorf(format string, args ...interface{}) {
- t.Logf(format, args...)
+ t.log(fmt.Sprintf(format, args...))
t.Fail()
}
// Fatal is equivalent to Log() followed by FailNow().
func (t *T) Fatal(args ...interface{}) {
- t.Log(args...)
+ t.log(fmt.Sprintln(args...))
t.FailNow()
}
// Fatalf is equivalent to Logf() followed by FailNow().
func (t *T) Fatalf(format string, args ...interface{}) {
- t.Logf(format, args...)
+ t.log(fmt.Sprintf(format, args...))
t.FailNow()
}
@@ -182,10 +201,10 @@ func Main(matchString func(pat, str string) (bool, error), tests []InternalTest,
testOk := RunTests(matchString, tests)
exampleOk := RunExamples(examples)
if !testOk || !exampleOk {
- fmt.Fprintln(os.Stderr, "FAIL")
+ fmt.Println("FAIL")
os.Exit(1)
}
- fmt.Fprintln(os.Stderr, "PASS")
+ fmt.Println("PASS")
stopAlarm()
RunBenchmarks(matchString, benchmarks)
after()
@@ -195,9 +214,9 @@ func report(t *T) {
tstr := fmt.Sprintf("(%.2f seconds)", float64(t.ns)/1e9)
format := "--- %s: %s %s\n%s"
if t.failed {
- fmt.Fprintf(os.Stderr, format, "FAIL", t.name, tstr, t.errors)
+ fmt.Printf(format, "FAIL", t.name, tstr, t.errors)
} else if *chatty {
- fmt.Fprintf(os.Stderr, format, "PASS", t.name, tstr, t.errors)
+ fmt.Printf(format, "PASS", t.name, tstr, t.errors)
}
}
@@ -217,7 +236,7 @@ func RunTests(matchString func(pat, str string) (bool, error), tests []InternalT
for i := 0; i < len(tests); i++ {
matched, err := matchString(*match, tests[i].Name)
if err != nil {
- println("invalid regexp for -test.run:", err.Error())
+ fmt.Fprintf(os.Stderr, "testing: invalid regexp for -test.run: %s\n", err)
os.Exit(1)
}
if !matched {
@@ -229,7 +248,7 @@ func RunTests(matchString func(pat, str string) (bool, error), tests []InternalT
}
t := &T{ch: ch, name: testName, startParallel: startParallel}
if *chatty {
- println("=== RUN", t.name)
+ fmt.Printf("=== RUN %s\n", t.name)
}
go tRunner(t, &tests[i])
out := <-t.ch
@@ -325,7 +344,7 @@ func parseCpuList() {
for _, val := range strings.Split(*cpuListStr, ",") {
cpu, err := strconv.Atoi(val)
if err != nil || cpu <= 0 {
- println("invalid value for -test.cpu")
+ fmt.Fprintf(os.Stderr, "testing: invalid value %q for -test.cpu", val)
os.Exit(1)
}
cpuList = append(cpuList, cpu)
diff --git a/libgo/go/text/tabwriter/tabwriter.go b/libgo/go/text/tabwriter/tabwriter.go
index c136ca2a175..201a685c630 100644
--- a/libgo/go/text/tabwriter/tabwriter.go
+++ b/libgo/go/text/tabwriter/tabwriter.go
@@ -13,7 +13,6 @@ package tabwriter
import (
"bytes"
"io"
- "os"
"unicode/utf8"
)
@@ -221,7 +220,7 @@ type osError struct {
func (b *Writer) write0(buf []byte) {
n, err := b.output.Write(buf)
if n != len(buf) && err == nil {
- err = os.EIO
+ err = io.ErrShortWrite
}
if err != nil {
panic(osError{err})
diff --git a/libgo/go/text/template/exec_test.go b/libgo/go/text/template/exec_test.go
index 57216676410..67b9416cd76 100644
--- a/libgo/go/text/template/exec_test.go
+++ b/libgo/go/text/template/exec_test.go
@@ -487,7 +487,11 @@ func testExecute(execTests []execTest, set *Set, t *testing.T) {
}
for _, test := range execTests {
tmpl := New(test.name).Funcs(funcs)
- _, err := tmpl.ParseInSet(test.input, set)
+ theSet := set
+ if theSet == nil {
+ theSet = new(Set)
+ }
+ _, err := tmpl.ParseInSet(test.input, theSet)
if err != nil {
t.Errorf("%s: parse error: %s", test.name, err)
continue
diff --git a/libgo/go/text/template/parse.go b/libgo/go/text/template/parse.go
index fa562141c29..7075f2ac20e 100644
--- a/libgo/go/text/template/parse.go
+++ b/libgo/go/text/template/parse.go
@@ -62,7 +62,7 @@ func (t *Template) Funcs(funcMap FuncMap) *Template {
// Parse parses the template definition string to construct an internal
// representation of the template for execution.
func (t *Template) Parse(s string) (tmpl *Template, err error) {
- t.Tree, err = parse.New(t.name).Parse(s, t.leftDelim, t.rightDelim, t.parseFuncs, builtins)
+ t.Tree, err = parse.New(t.name).Parse(s, t.leftDelim, t.rightDelim, nil, t.parseFuncs, builtins)
if err != nil {
return nil, err
}
@@ -71,19 +71,13 @@ func (t *Template) Parse(s string) (tmpl *Template, err error) {
// ParseInSet parses the template definition string to construct an internal
// representation of the template for execution. It also adds the template
-// to the set. It is an error if s is already defined in the set.
+// to the set, which must not be nil. It is an error if s is already defined in the set.
// Function bindings are checked against those in the set.
func (t *Template) ParseInSet(s string, set *Set) (tmpl *Template, err error) {
- var setFuncs FuncMap
- if set != nil {
- setFuncs = set.parseFuncs
- }
- t.Tree, err = parse.New(t.name).Parse(s, t.leftDelim, t.rightDelim, t.parseFuncs, setFuncs, builtins)
+ t.Tree, err = parse.New(t.name).Parse(s, t.leftDelim, t.rightDelim, set.trees, t.parseFuncs, set.parseFuncs, builtins)
if err != nil {
return nil, err
}
- if set != nil {
- err = set.add(t)
- }
+ err = set.add(t)
return t, err
}
diff --git a/libgo/go/text/template/parse/parse.go b/libgo/go/text/template/parse/parse.go
index 1b6ab3af4f0..e906ee83aac 100644
--- a/libgo/go/text/template/parse/parse.go
+++ b/libgo/go/text/template/parse/parse.go
@@ -146,29 +146,70 @@ func (t *Tree) atEOF() bool {
// Parse parses the template definition string to construct an internal
// representation of the template for execution. If either action delimiter
// string is empty, the default ("{{" or "}}") is used.
-func (t *Tree) Parse(s, leftDelim, rightDelim string, funcs ...map[string]interface{}) (tree *Tree, err error) {
+func (t *Tree) Parse(s, leftDelim, rightDelim string, treeSet map[string]*Tree, funcs ...map[string]interface{}) (tree *Tree, err error) {
defer t.recover(&err)
t.startParse(funcs, lex(t.Name, s, leftDelim, rightDelim))
- t.parse(true)
+ t.parse(treeSet)
t.stopParse()
return t, nil
}
-// parse is the helper for Parse.
-// It triggers an error if we expect EOF but don't reach it.
-func (t *Tree) parse(toEOF bool) (next Node) {
- t.Root, next = t.itemList(true)
- if toEOF && next != nil {
- t.errorf("unexpected %s", next)
+// parse is the top-level parser for a template, essentially the same
+// as itemList except it also parses {{define}} actions.
+// It runs to EOF.
+func (t *Tree) parse(treeSet map[string]*Tree) (next Node) {
+ t.Root = newList()
+ for t.peek().typ != itemEOF {
+ if t.peek().typ == itemLeftDelim {
+ delim := t.next()
+ if t.next().typ == itemDefine {
+ newT := New("new definition") // name will be updated once we know it.
+ newT.startParse(t.funcs, t.lex)
+ newT.parseDefinition(treeSet)
+ continue
+ }
+ t.backup2(delim)
+ }
+ n := t.textOrAction()
+ if n.Type() == nodeEnd {
+ t.errorf("unexpected %s", n)
+ }
+ t.Root.append(n)
}
- return next
+ return nil
+}
+
+// parseDefinition parses a {{define}} ... {{end}} template definition and
+// installs the definition in the treeSet map. The "define" keyword has already
+// been scanned.
+func (t *Tree) parseDefinition(treeSet map[string]*Tree) {
+ if treeSet == nil {
+ t.errorf("no set specified for template definition")
+ }
+ const context = "define clause"
+ name := t.expect(itemString, context)
+ var err error
+ t.Name, err = strconv.Unquote(name.val)
+ if err != nil {
+ t.error(err)
+ }
+ t.expect(itemRightDelim, context)
+ var end Node
+ t.Root, end = t.itemList()
+ if end.Type() != nodeEnd {
+ t.errorf("unexpected %s in %s", end, context)
+ }
+ t.stopParse()
+ if _, present := treeSet[t.Name]; present {
+ t.errorf("template: %q multiply defined", name)
+ }
+ treeSet[t.Name] = t
}
// itemList:
// textOrAction*
-// Terminates at EOF and at {{end}} or {{else}}, which is returned separately.
-// The toEOF flag tells whether we expect to reach EOF.
-func (t *Tree) itemList(toEOF bool) (list *ListNode, next Node) {
+// Terminates at {{end}} or {{else}}, returned separately.
+func (t *Tree) itemList() (list *ListNode, next Node) {
list = newList()
for t.peek().typ != itemEOF {
n := t.textOrAction()
@@ -178,10 +219,8 @@ func (t *Tree) itemList(toEOF bool) (list *ListNode, next Node) {
}
list.append(n)
}
- if !toEOF {
- t.unexpected(t.next(), "input")
- }
- return list, nil
+ t.errorf("unexpected EOF")
+ return
}
// textOrAction:
@@ -276,11 +315,11 @@ func (t *Tree) parseControl(context string) (lineNum int, pipe *PipeNode, list,
defer t.popVars(len(t.vars))
pipe = t.pipeline(context)
var next Node
- list, next = t.itemList(false)
+ list, next = t.itemList()
switch next.Type() {
case nodeEnd: //done
case nodeElse:
- elseList, next = t.itemList(false)
+ elseList, next = t.itemList()
if next.Type() != nodeEnd {
t.errorf("expected end; found %s", next)
}
diff --git a/libgo/go/text/template/parse/parse_test.go b/libgo/go/text/template/parse/parse_test.go
index f05f6e3874c..5c10086cc7c 100644
--- a/libgo/go/text/template/parse/parse_test.go
+++ b/libgo/go/text/template/parse/parse_test.go
@@ -236,7 +236,7 @@ var builtins = map[string]interface{}{
func TestParse(t *testing.T) {
for _, test := range parseTests {
- tmpl, err := New(test.name).Parse(test.input, "", "", builtins)
+ tmpl, err := New(test.name).Parse(test.input, "", "", nil, builtins)
switch {
case err == nil && !test.ok:
t.Errorf("%q: expected error; got none", test.name)
diff --git a/libgo/go/text/template/parse/set.go b/libgo/go/text/template/parse/set.go
index d363eeff080..55f3ceb3d51 100644
--- a/libgo/go/text/template/parse/set.go
+++ b/libgo/go/text/template/parse/set.go
@@ -4,46 +4,12 @@
package parse
-import (
- "fmt"
- "strconv"
-)
-
// Set returns a slice of Trees created by parsing the template set
// definition in the argument string. If an error is encountered,
// parsing stops and an empty slice is returned with the error.
func Set(text, leftDelim, rightDelim string, funcs ...map[string]interface{}) (tree map[string]*Tree, err error) {
tree = make(map[string]*Tree)
- defer (*Tree)(nil).recover(&err)
- lex := lex("set", text, leftDelim, rightDelim)
- const context = "define clause"
- for {
- t := New("set") // name will be updated once we know it.
- t.startParse(funcs, lex)
- // Expect EOF or "{{ define name }}".
- if t.atEOF() {
- break
- }
- t.expect(itemLeftDelim, context)
- t.expect(itemDefine, context)
- name := t.expect(itemString, context)
- t.Name, err = strconv.Unquote(name.val)
- if err != nil {
- t.error(err)
- }
- t.expect(itemRightDelim, context)
- end := t.parse(false)
- if end == nil {
- t.errorf("unexpected EOF in %s", context)
- }
- if end.Type() != nodeEnd {
- t.errorf("unexpected %s in %s", end, context)
- }
- t.stopParse()
- if _, present := tree[t.Name]; present {
- return nil, fmt.Errorf("template: %q multiply defined", name)
- }
- tree[t.Name] = t
- }
+ // Top-level template name is needed but unused. TODO: clean this up.
+ _, err = New("ROOT").Parse(text, leftDelim, rightDelim, tree, funcs...)
return
}
diff --git a/libgo/go/text/template/set.go b/libgo/go/text/template/set.go
index 747cc7802b4..48417044e77 100644
--- a/libgo/go/text/template/set.go
+++ b/libgo/go/text/template/set.go
@@ -16,6 +16,7 @@ import (
// A template may be a member of multiple sets.
type Set struct {
tmpl map[string]*Template
+ trees map[string]*parse.Tree // maintained by parse package
leftDelim string
rightDelim string
parseFuncs FuncMap
diff --git a/libgo/go/time/sleep.go b/libgo/go/time/sleep.go
index 314622d0dc9..967fca09b99 100644
--- a/libgo/go/time/sleep.go
+++ b/libgo/go/time/sleep.go
@@ -4,54 +4,60 @@
package time
-import (
- "container/heap"
- "sync"
-)
+// Interface to timers implemented in package runtime.
+// Must be in sync with ../runtime/runtime.h:/^struct.Timer$
+type runtimeTimer struct {
+ i int32
+ when int64
+ period int64
+ f func(int64, interface{})
+ arg interface{}
+}
+
+func startTimer(*runtimeTimer)
+func stopTimer(*runtimeTimer) bool
// The Timer type represents a single event.
-// When the Timer expires, the current time will be sent on C
-// unless the Timer represents an AfterFunc event.
+// When the Timer expires, the current time will be sent on C,
+// unless the Timer was created by AfterFunc.
type Timer struct {
C <-chan int64
- t int64 // The absolute time that the event should fire.
- f func(int64) // The function to call when the event fires.
- i int // The event's index inside eventHeap.
+ r runtimeTimer
}
-type timerHeap []*Timer
-
-// forever is the absolute time (in ns) of an event that is forever away.
-const forever = 1 << 62
-
-// maxSleepTime is the maximum length of time that a sleeper
-// sleeps for before checking if it is defunct.
-const maxSleepTime = 1e9
-
-var (
- // timerMutex guards the variables inside this var group.
- timerMutex sync.Mutex
-
- // timers holds a binary heap of pending events, terminated with a sentinel.
- timers timerHeap
-
- // currentSleeper is an ever-incrementing counter which represents
- // the current sleeper. It allows older sleepers to detect that they are
- // defunct and exit.
- currentSleeper int64
-)
-
-func init() {
- timers.Push(&Timer{t: forever}) // sentinel
+// Stop prevents the Timer from firing.
+// It returns true if the call stops the timer, false if the timer has already
+// expired or stopped.
+func (t *Timer) Stop() (ok bool) {
+ return stopTimer(&t.r)
}
// NewTimer creates a new Timer that will send
// the current time on its channel after at least ns nanoseconds.
func NewTimer(ns int64) *Timer {
c := make(chan int64, 1)
- e := after(ns, func(t int64) { c <- t })
- e.C = c
- return e
+ t := &Timer{
+ C: c,
+ r: runtimeTimer{
+ when: Nanoseconds() + ns,
+ f: sendTime,
+ arg: c,
+ },
+ }
+ startTimer(&t.r)
+ return t
+}
+
+func sendTime(now int64, c interface{}) {
+ // Non-blocking send of time on c.
+ // Used in NewTimer, it cannot block anyway (buffer).
+ // Used in NewTicker, dropping sends on the floor is
+ // the desired behavior when the reader gets behind,
+ // because the sends are periodic.
+ select {
+ case c.(chan int64) <- now:
+ default:
+ }
}
// After waits at least ns nanoseconds before sending the current time
@@ -65,113 +71,17 @@ func After(ns int64) <-chan int64 {
// in its own goroutine. It returns a Timer that can
// be used to cancel the call using its Stop method.
func AfterFunc(ns int64, f func()) *Timer {
- return after(ns, func(_ int64) {
- go f()
- })
-}
-
-// Stop prevents the Timer from firing.
-// It returns true if the call stops the timer, false if the timer has already
-// expired or stopped.
-func (e *Timer) Stop() (ok bool) {
- timerMutex.Lock()
- // Avoid removing the first event in the queue so that
- // we don't start a new sleeper unnecessarily.
- if e.i > 0 {
- heap.Remove(timers, e.i)
- }
- ok = e.f != nil
- e.f = nil
- timerMutex.Unlock()
- return
-}
-
-// after is the implementation of After and AfterFunc.
-// When the current time is after ns, it calls f with the current time.
-// It assumes that f will not block.
-func after(ns int64, f func(int64)) (e *Timer) {
- now := Nanoseconds()
- t := now + ns
- if ns > 0 && t < now {
- panic("time: time overflow")
- }
- timerMutex.Lock()
- t0 := timers[0].t
- e = &Timer{nil, t, f, -1}
- heap.Push(timers, e)
- // Start a new sleeper if the new event is before
- // the first event in the queue. If the length of time
- // until the new event is at least maxSleepTime,
- // then we're guaranteed that the sleeper will wake up
- // in time to service it, so no new sleeper is needed.
- if t0 > t && (t0 == forever || ns < maxSleepTime) {
- currentSleeper++
- go sleeper(currentSleeper)
- }
- timerMutex.Unlock()
- return
-}
-
-// sleeper continually looks at the earliest event in the queue, waits until it happens,
-// then removes any events in the queue that are due. It stops when the queue
-// is empty or when another sleeper has been started.
-func sleeper(sleeperId int64) {
- timerMutex.Lock()
- e := timers[0]
- t := Nanoseconds()
- for e.t != forever {
- if dt := e.t - t; dt > 0 {
- if dt > maxSleepTime {
- dt = maxSleepTime
- }
- timerMutex.Unlock()
- sysSleep(dt)
- timerMutex.Lock()
- if currentSleeper != sleeperId {
- // Another sleeper has been started, making this one redundant.
- break
- }
- }
- e = timers[0]
- t = Nanoseconds()
- for t >= e.t {
- if e.f != nil {
- e.f(t)
- e.f = nil
- }
- heap.Pop(timers)
- e = timers[0]
- }
+ t := &Timer{
+ r: runtimeTimer{
+ when: Nanoseconds() + ns,
+ f: goFunc,
+ arg: f,
+ },
}
- timerMutex.Unlock()
-}
-
-func (timerHeap) Len() int {
- return len(timers)
-}
-
-func (timerHeap) Less(i, j int) bool {
- return timers[i].t < timers[j].t
-}
-
-func (timerHeap) Swap(i, j int) {
- timers[i], timers[j] = timers[j], timers[i]
- timers[i].i = i
- timers[j].i = j
-}
-
-func (timerHeap) Push(x interface{}) {
- e := x.(*Timer)
- e.i = len(timers)
- timers = append(timers, e)
+ startTimer(&t.r)
+ return t
}
-func (timerHeap) Pop() interface{} {
- // TODO: possibly shrink array.
- n := len(timers) - 1
- e := timers[n]
- timers[n] = nil
- timers = timers[0:n]
- e.i = -1
- return e
+func goFunc(now int64, arg interface{}) {
+ go arg.(func())()
}
diff --git a/libgo/go/time/sleep_test.go b/libgo/go/time/sleep_test.go
index 0662e3359cf..9171da3af1c 100644
--- a/libgo/go/time/sleep_test.go
+++ b/libgo/go/time/sleep_test.go
@@ -7,7 +7,9 @@ package time_test
import (
"errors"
"fmt"
+ "runtime"
"sort"
+ "sync/atomic"
"testing"
. "time"
)
@@ -47,6 +49,23 @@ func TestAfterFunc(t *testing.T) {
<-c
}
+func TestAfterStress(t *testing.T) {
+ stop := uint32(0)
+ go func() {
+ for atomic.LoadUint32(&stop) == 0 {
+ runtime.GC()
+ // Need to yield, because otherwise
+ // the main goroutine will never set the stop flag.
+ runtime.Gosched()
+ }
+ }()
+ c := Tick(1)
+ for i := 0; i < 100; i++ {
+ <-c
+ }
+ atomic.StoreUint32(&stop, 1)
+}
+
func BenchmarkAfterFunc(b *testing.B) {
i := b.N
c := make(chan bool)
diff --git a/libgo/go/time/sys.go b/libgo/go/time/sys.go
index ca1d334a5b7..a5e529b814a 100644
--- a/libgo/go/time/sys.go
+++ b/libgo/go/time/sys.go
@@ -17,25 +17,4 @@ func Seconds() int64 {
func Nanoseconds() int64
// Sleep pauses the current goroutine for at least ns nanoseconds.
-// Higher resolution sleeping may be provided by syscall.Nanosleep
-// on some operating systems.
-func Sleep(ns int64) error {
- _, err := sleep(Nanoseconds(), ns)
- return err
-}
-
-// sleep takes the current time and a duration,
-// pauses for at least ns nanoseconds, and
-// returns the current time and an error.
-func sleep(t, ns int64) (int64, error) {
- // TODO(cw): use monotonic-time once it's available
- end := t + ns
- for t < end {
- err := sysSleep(end - t)
- if err != nil {
- return 0, err
- }
- t = Nanoseconds()
- }
- return t, nil
-}
+func Sleep(ns int64)
diff --git a/libgo/go/time/sys_plan9.go b/libgo/go/time/sys_plan9.go
index a630b3ee030..e58fb519ea3 100644
--- a/libgo/go/time/sys_plan9.go
+++ b/libgo/go/time/sys_plan9.go
@@ -4,19 +4,6 @@
package time
-import (
- "os"
- "syscall"
-)
-
-func sysSleep(t int64) error {
- err := syscall.Sleep(t)
- if err != nil {
- return os.NewSyscallError("sleep", err)
- }
- return nil
-}
-
// for testing: whatever interrupts a sleep
func interrupt() {
// cannot predict pid, don't want to kill group
diff --git a/libgo/go/time/sys_unix.go b/libgo/go/time/sys_unix.go
index 17a6a2d63e0..3d313228b01 100644
--- a/libgo/go/time/sys_unix.go
+++ b/libgo/go/time/sys_unix.go
@@ -11,14 +11,6 @@ import (
"syscall"
)
-func sysSleep(t int64) error {
- errno := syscall.Sleep(t)
- if errno != 0 && errno != syscall.EINTR {
- return os.NewSyscallError("sleep", errno)
- }
- return nil
-}
-
// for testing: whatever interrupts a sleep
func interrupt() {
syscall.Kill(os.Getpid(), syscall.SIGCHLD)
diff --git a/libgo/go/time/sys_windows.go b/libgo/go/time/sys_windows.go
index f9d6e89281c..8c7242f4275 100644
--- a/libgo/go/time/sys_windows.go
+++ b/libgo/go/time/sys_windows.go
@@ -4,19 +4,6 @@
package time
-import (
- "os"
- "syscall"
-)
-
-func sysSleep(t int64) error {
- errno := syscall.Sleep(t)
- if errno != 0 && errno != syscall.EINTR {
- return os.NewSyscallError("sleep", errno)
- }
- return nil
-}
-
// for testing: whatever interrupts a sleep
func interrupt() {
}
diff --git a/libgo/go/time/tick.go b/libgo/go/time/tick.go
index 92f9eb893e4..95941a1e819 100644
--- a/libgo/go/time/tick.go
+++ b/libgo/go/time/tick.go
@@ -4,156 +4,15 @@
package time
-import (
- "errors"
- "sync"
-)
+import "errors"
// A Ticker holds a synchronous channel that delivers `ticks' of a clock
// at intervals.
type Ticker struct {
- C <-chan int64 // The channel on which the ticks are delivered.
- c chan<- int64 // The same channel, but the end we use.
- ns int64
- shutdown chan bool // Buffered channel used to signal shutdown.
- nextTick int64
- next *Ticker
+ C <-chan int64 // The channel on which the ticks are delivered.
+ r runtimeTimer
}
-// Stop turns off a ticker. After Stop, no more ticks will be sent.
-func (t *Ticker) Stop() {
- select {
- case t.shutdown <- true:
- // ok
- default:
- // Stop in progress already
- }
-}
-
-// Tick is a convenience wrapper for NewTicker providing access to the ticking
-// channel only. Useful for clients that have no need to shut down the ticker.
-func Tick(ns int64) <-chan int64 {
- if ns <= 0 {
- return nil
- }
- return NewTicker(ns).C
-}
-
-type alarmer struct {
- wakeUp chan bool // wakeup signals sent/received here
- wakeMeAt chan int64
- wakeTime int64
-}
-
-// Set alarm to go off at time ns, if not already set earlier.
-func (a *alarmer) set(ns int64) {
- switch {
- case a.wakeTime > ns:
- // Next tick we expect is too late; shut down the late runner
- // and (after fallthrough) start a new wakeLoop.
- close(a.wakeMeAt)
- fallthrough
- case a.wakeMeAt == nil:
- // There's no wakeLoop, start one.
- a.wakeMeAt = make(chan int64)
- a.wakeUp = make(chan bool, 1)
- go wakeLoop(a.wakeMeAt, a.wakeUp)
- fallthrough
- case a.wakeTime == 0:
- // Nobody else is waiting; it's just us.
- a.wakeTime = ns
- a.wakeMeAt <- ns
- default:
- // There's already someone scheduled.
- }
-}
-
-// Channel to notify tickerLoop of new Tickers being created.
-var newTicker chan *Ticker
-
-func startTickerLoop() {
- newTicker = make(chan *Ticker)
- go tickerLoop()
-}
-
-// wakeLoop delivers ticks at scheduled times, sleeping until the right moment.
-// If another, earlier Ticker is created while it sleeps, tickerLoop() will start a new
-// wakeLoop and signal that this one is done by closing the wakeMeAt channel.
-func wakeLoop(wakeMeAt chan int64, wakeUp chan bool) {
- for wakeAt := range wakeMeAt {
- Sleep(wakeAt - Nanoseconds())
- wakeUp <- true
- }
-}
-
-// A single tickerLoop serves all ticks to Tickers. It waits for two events:
-// either the creation of a new Ticker or a tick from the alarm,
-// signaling a time to wake up one or more Tickers.
-func tickerLoop() {
- // Represents the next alarm to be delivered.
- var alarm alarmer
- var now, wakeTime int64
- var tickers *Ticker
- for {
- select {
- case t := <-newTicker:
- // Add Ticker to list
- t.next = tickers
- tickers = t
- // Arrange for a new alarm if this one precedes the existing one.
- alarm.set(t.nextTick)
- case <-alarm.wakeUp:
- now = Nanoseconds()
- wakeTime = now + 1e15 // very long in the future
- var prev *Ticker = nil
- // Scan list of tickers, delivering updates to those
- // that need it and determining the next wake time.
- // TODO(r): list should be sorted in time order.
- for t := tickers; t != nil; t = t.next {
- select {
- case <-t.shutdown:
- // Ticker is done; remove it from list.
- if prev == nil {
- tickers = t.next
- } else {
- prev.next = t.next
- }
- continue
- default:
- }
- if t.nextTick <= now {
- if len(t.c) == 0 {
- // Only send if there's room. We must not block.
- // The channel is allocated with a one-element
- // buffer, which is sufficient: if he hasn't picked
- // up the last tick, no point in sending more.
- t.c <- now
- }
- t.nextTick += t.ns
- if t.nextTick <= now {
- // Still behind; advance in one big step.
- t.nextTick += (now - t.nextTick + t.ns) / t.ns * t.ns
- }
- }
- if t.nextTick < wakeTime {
- wakeTime = t.nextTick
- }
- prev = t
- }
- if tickers != nil {
- // Please send wakeup at earliest required time.
- // If there are no tickers, don't bother.
- alarm.wakeTime = wakeTime
- alarm.wakeMeAt <- wakeTime
- } else {
- alarm.wakeTime = 0
- }
- }
- }
-}
-
-var onceStartTickerLoop sync.Once
-
// NewTicker returns a new Ticker containing a channel that will
// send the time, in nanoseconds, every ns nanoseconds. It adjusts the
// intervals to make up for pauses in delivery of the ticks. The value of
@@ -162,16 +21,33 @@ func NewTicker(ns int64) *Ticker {
if ns <= 0 {
panic(errors.New("non-positive interval for NewTicker"))
}
- c := make(chan int64, 1) // See comment on send in tickerLoop
+ // Give the channel a 1-element time buffer.
+ // If the client falls behind while reading, we drop ticks
+ // on the floor until the client catches up.
+ c := make(chan int64, 1)
t := &Ticker{
- C: c,
- c: c,
- ns: ns,
- shutdown: make(chan bool, 1),
- nextTick: Nanoseconds() + ns,
+ C: c,
+ r: runtimeTimer{
+ when: Nanoseconds() + ns,
+ period: ns,
+ f: sendTime,
+ arg: c,
+ },
}
- onceStartTickerLoop.Do(startTickerLoop)
- // must be run in background so global Tickers can be created
- go func() { newTicker <- t }()
+ startTimer(&t.r)
return t
}
+
+// Stop turns off a ticker. After Stop, no more ticks will be sent.
+func (t *Ticker) Stop() {
+ stopTimer(&t.r)
+}
+
+// Tick is a convenience wrapper for NewTicker providing access to the ticking
+// channel only. Useful for clients that have no need to shut down the ticker.
+func Tick(ns int64) <-chan int64 {
+ if ns <= 0 {
+ return nil
+ }
+ return NewTicker(ns).C
+}
diff --git a/libgo/go/time/time.go b/libgo/go/time/time.go
index 859b3167278..e11d17731b4 100644
--- a/libgo/go/time/time.go
+++ b/libgo/go/time/time.go
@@ -237,3 +237,63 @@ func (t *Time) Weekday() int {
}
return weekday
}
+
+// julianDayNumber returns the time's Julian Day Number
+// relative to the epoch 12:00 January 1, 4713 BC, Monday.
+func julianDayNumber(year int64, month, day int) int64 {
+ a := int64(14-month) / 12
+ y := year + 4800 - a
+ m := int64(month) + 12*a - 3
+ return int64(day) + (153*m+2)/5 + 365*y + y/4 - y/100 + y/400 - 32045
+}
+
+// startOfFirstWeek returns the julian day number of the first day
+// of the first week of the given year.
+func startOfFirstWeek(year int64) (d int64) {
+ jan01 := julianDayNumber(year, 1, 1)
+ weekday := (jan01 % 7) + 1
+ if weekday <= 4 {
+ d = jan01 - weekday + 1
+ } else {
+ d = jan01 + 8 - weekday
+ }
+ return
+}
+
+// dayOfWeek returns the weekday of the given date.
+func dayOfWeek(year int64, month, day int) int {
+ t := Time{Year: year, Month: month, Day: day}
+ return t.Weekday()
+}
+
+// ISOWeek returns the time's year and week number according to ISO 8601.
+// Week ranges from 1 to 53. Jan 01 to Jan 03 of year n might belong to
+// week 52 or 53 of year n-1, and Dec 29 to Dec 31 might belong to week 1
+// of year n+1.
+func (t *Time) ISOWeek() (year int64, week int) {
+ d := julianDayNumber(t.Year, t.Month, t.Day)
+ week1Start := startOfFirstWeek(t.Year)
+
+ if d < week1Start {
+ // Previous year, week 52 or 53
+ year = t.Year - 1
+ if dayOfWeek(t.Year-1, 1, 1) == 4 || dayOfWeek(t.Year-1, 12, 31) == 4 {
+ week = 53
+ } else {
+ week = 52
+ }
+ return
+ }
+
+ if d < startOfFirstWeek(t.Year+1) {
+ // Current year, week 01..52(,53)
+ year = t.Year
+ week = int((d-week1Start)/7 + 1)
+ return
+ }
+
+ // Next year, week 1
+ year = t.Year + 1
+ week = 1
+ return
+}
diff --git a/libgo/go/time/time_test.go b/libgo/go/time/time_test.go
index 8b373a13bc2..01b8bea4aad 100644
--- a/libgo/go/time/time_test.go
+++ b/libgo/go/time/time_test.go
@@ -478,6 +478,68 @@ func TestMinutesInTimeZone(t *testing.T) {
}
}
+type ISOWeekTest struct {
+ year int64 // year
+ month, day int // month and day
+ yex int64 // expected year
+ wex int // expected week
+}
+
+var isoWeekTests = []ISOWeekTest{
+ {1981, 1, 1, 1981, 1}, {1982, 1, 1, 1981, 53}, {1983, 1, 1, 1982, 52},
+ {1984, 1, 1, 1983, 52}, {1985, 1, 1, 1985, 1}, {1986, 1, 1, 1986, 1},
+ {1987, 1, 1, 1987, 1}, {1988, 1, 1, 1987, 53}, {1989, 1, 1, 1988, 52},
+ {1990, 1, 1, 1990, 1}, {1991, 1, 1, 1991, 1}, {1992, 1, 1, 1992, 1},
+ {1993, 1, 1, 1992, 53}, {1994, 1, 1, 1993, 52}, {1995, 1, 2, 1995, 1},
+ {1996, 1, 1, 1996, 1}, {1996, 1, 7, 1996, 1}, {1996, 1, 8, 1996, 2},
+ {1997, 1, 1, 1997, 1}, {1998, 1, 1, 1998, 1}, {1999, 1, 1, 1998, 53},
+ {2000, 1, 1, 1999, 52}, {2001, 1, 1, 2001, 1}, {2002, 1, 1, 2002, 1},
+ {2003, 1, 1, 2003, 1}, {2004, 1, 1, 2004, 1}, {2005, 1, 1, 2004, 53},
+ {2006, 1, 1, 2005, 52}, {2007, 1, 1, 2007, 1}, {2008, 1, 1, 2008, 1},
+ {2009, 1, 1, 2009, 1}, {2010, 1, 1, 2009, 53}, {2010, 1, 1, 2009, 53},
+ {2011, 1, 1, 2010, 52}, {2011, 1, 2, 2010, 52}, {2011, 1, 3, 2011, 1},
+ {2011, 1, 4, 2011, 1}, {2011, 1, 5, 2011, 1}, {2011, 1, 6, 2011, 1},
+ {2011, 1, 7, 2011, 1}, {2011, 1, 8, 2011, 1}, {2011, 1, 9, 2011, 1},
+ {2011, 1, 10, 2011, 2}, {2011, 1, 11, 2011, 2}, {2011, 6, 12, 2011, 23},
+ {2011, 6, 13, 2011, 24}, {2011, 12, 25, 2011, 51}, {2011, 12, 26, 2011, 52},
+ {2011, 12, 27, 2011, 52}, {2011, 12, 28, 2011, 52}, {2011, 12, 29, 2011, 52},
+ {2011, 12, 30, 2011, 52}, {2011, 12, 31, 2011, 52}, {1995, 1, 1, 1994, 52},
+ {2012, 1, 1, 2011, 52}, {2012, 1, 2, 2012, 1}, {2012, 1, 8, 2012, 1},
+ {2012, 1, 9, 2012, 2}, {2012, 12, 23, 2012, 51}, {2012, 12, 24, 2012, 52},
+ {2012, 12, 30, 2012, 52}, {2012, 12, 31, 2013, 1}, {2013, 1, 1, 2013, 1},
+ {2013, 1, 6, 2013, 1}, {2013, 1, 7, 2013, 2}, {2013, 12, 22, 2013, 51},
+ {2013, 12, 23, 2013, 52}, {2013, 12, 29, 2013, 52}, {2013, 12, 30, 2014, 1},
+ {2014, 1, 1, 2014, 1}, {2014, 1, 5, 2014, 1}, {2014, 1, 6, 2014, 2},
+ {2015, 1, 1, 2015, 1}, {2016, 1, 1, 2015, 53}, {2017, 1, 1, 2016, 52},
+ {2018, 1, 1, 2018, 1}, {2019, 1, 1, 2019, 1}, {2020, 1, 1, 2020, 1},
+ {2021, 1, 1, 2020, 53}, {2022, 1, 1, 2021, 52}, {2023, 1, 1, 2022, 52},
+ {2024, 1, 1, 2024, 1}, {2025, 1, 1, 2025, 1}, {2026, 1, 1, 2026, 1},
+ {2027, 1, 1, 2026, 53}, {2028, 1, 1, 2027, 52}, {2029, 1, 1, 2029, 1},
+ {2030, 1, 1, 2030, 1}, {2031, 1, 1, 2031, 1}, {2032, 1, 1, 2032, 1},
+ {2033, 1, 1, 2032, 53}, {2034, 1, 1, 2033, 52}, {2035, 1, 1, 2035, 1},
+ {2036, 1, 1, 2036, 1}, {2037, 1, 1, 2037, 1}, {2038, 1, 1, 2037, 53},
+ {2039, 1, 1, 2038, 52}, {2040, 1, 1, 2039, 52},
+}
+
+func TestISOWeek(t *testing.T) {
+ // Selected dates and corner cases
+ for _, wt := range isoWeekTests {
+ dt := &Time{Year: wt.year, Month: wt.month, Day: wt.day}
+ y, w := dt.ISOWeek()
+ if w != wt.wex || y != wt.yex {
+ t.Errorf("got %d/%d; expected %d/%d for %d-%02d-%02d",
+ y, w, wt.yex, wt.wex, wt.year, wt.month, wt.day)
+ }
+ }
+
+ // The only real invariant: Jan 04 is in week 1
+ for year := int64(1950); year < 2100; year++ {
+ if y, w := (&Time{Year: year, Month: 1, Day: 4}).ISOWeek(); y != year || w != 1 {
+ t.Errorf("got %d/%d; expected %d/1 for Jan 04", y, w, year)
+ }
+ }
+}
+
func BenchmarkSeconds(b *testing.B) {
for i := 0; i < b.N; i++ {
Seconds()
diff --git a/libgo/go/time/zoneinfo_unix.go b/libgo/go/time/zoneinfo_unix.go
index 0dc42353136..b552e589aa9 100644
--- a/libgo/go/time/zoneinfo_unix.go
+++ b/libgo/go/time/zoneinfo_unix.go
@@ -12,7 +12,7 @@
package time
import (
- "io/ioutil"
+ "bytes"
"os"
)
@@ -180,11 +180,17 @@ func parseinfo(bytes []byte) (zt []zonetime, ok bool) {
}
func readinfofile(name string) ([]zonetime, bool) {
- buf, err := ioutil.ReadFile(name)
+ var b bytes.Buffer
+
+ f, err := os.Open(name)
if err != nil {
return nil, false
}
- return parseinfo(buf)
+ defer f.Close()
+ if _, err := b.ReadFrom(f); err != nil {
+ return nil, false
+ }
+ return parseinfo(b.Bytes())
}
func setupTestingZone() {
diff --git a/libgo/go/time/zoneinfo_windows.go b/libgo/go/time/zoneinfo_windows.go
index ba152e0882a..995fd44dc06 100644
--- a/libgo/go/time/zoneinfo_windows.go
+++ b/libgo/go/time/zoneinfo_windows.go
@@ -161,7 +161,7 @@ var onceSetupZone sync.Once
func setupZone() {
var i syscall.Timezoneinformation
- if _, e := syscall.GetTimeZoneInformation(&i); e != 0 {
+ if _, e := syscall.GetTimeZoneInformation(&i); e != nil {
initError = os.NewSyscallError("GetTimeZoneInformation", e)
return
}
diff --git a/libgo/go/websocket/websocket.go b/libgo/go/websocket/websocket.go
index 1e4036ce391..df4416e22ed 100644
--- a/libgo/go/websocket/websocket.go
+++ b/libgo/go/websocket/websocket.go
@@ -10,12 +10,12 @@ import (
"bufio"
"crypto/tls"
"encoding/json"
+ "errors"
"io"
"io/ioutil"
"net"
"net/http"
"net/url"
- "os"
"sync"
)
@@ -243,12 +243,14 @@ func (ws *Conn) RemoteAddr() net.Addr {
return &Addr{ws.config.Origin}
}
+var errSetTimeout = errors.New("websocket: cannot set timeout: not using a net.Conn")
+
// SetTimeout sets the connection's network timeout in nanoseconds.
func (ws *Conn) SetTimeout(nsec int64) error {
if conn, ok := ws.rwc.(net.Conn); ok {
return conn.SetTimeout(nsec)
}
- return os.EINVAL
+ return errSetTimeout
}
// SetReadTimeout sets the connection's network read timeout in nanoseconds.
@@ -256,7 +258,7 @@ func (ws *Conn) SetReadTimeout(nsec int64) error {
if conn, ok := ws.rwc.(net.Conn); ok {
return conn.SetReadTimeout(nsec)
}
- return os.EINVAL
+ return errSetTimeout
}
// SetWriteTimeout sets the connection's network write timeout in nanoseconds.
@@ -264,7 +266,7 @@ func (ws *Conn) SetWriteTimeout(nsec int64) error {
if conn, ok := ws.rwc.(net.Conn); ok {
return conn.SetWriteTimeout(nsec)
}
- return os.EINVAL
+ return errSetTimeout
}
// Config returns the WebSocket config.