]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libgo: Update to weekly.2011-11-18.
authorIan Lance Taylor <ian@gcc.gnu.org>
Mon, 12 Dec 2011 23:40:51 +0000 (23:40 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Mon, 12 Dec 2011 23:40:51 +0000 (23:40 +0000)
From-SVN: r182266

223 files changed:
libgo/MERGE
libgo/Makefile.am
libgo/Makefile.in
libgo/go/bufio/bufio_test.go
libgo/go/builtin/builtin.go
libgo/go/bytes/bytes_test.go
libgo/go/compress/lzw/reader.go
libgo/go/compress/lzw/writer.go
libgo/go/compress/lzw/writer_test.go
libgo/go/compress/zlib/writer_test.go
libgo/go/crypto/aes/cipher.go
libgo/go/crypto/blowfish/cipher.go
libgo/go/crypto/rand/rand_windows.go
libgo/go/crypto/rand/util.go
libgo/go/crypto/tls/conn.go
libgo/go/crypto/tls/handshake_messages.go
libgo/go/crypto/tls/handshake_messages_test.go
libgo/go/crypto/tls/root_windows.go
libgo/go/crypto/xtea/cipher.go
libgo/go/encoding/json/bench_test.go [new file with mode: 0644]
libgo/go/encoding/json/decode.go
libgo/go/encoding/json/scanner.go
libgo/go/encoding/json/scanner_test.go
libgo/go/encoding/xml/xml_test.go
libgo/go/exp/inotify/inotify_linux.go
libgo/go/exp/sql/convert.go
libgo/go/exp/sql/driver/driver.go
libgo/go/exp/sql/fakedb_test.go
libgo/go/exp/sql/sql.go
libgo/go/exp/sql/sql_test.go
libgo/go/exp/ssh/cipher.go [new file with mode: 0644]
libgo/go/exp/ssh/cipher_test.go [new file with mode: 0644]
libgo/go/exp/ssh/client.go
libgo/go/exp/ssh/client_auth.go
libgo/go/exp/ssh/client_auth_test.go [new file with mode: 0644]
libgo/go/exp/ssh/client_func_test.go [new file with mode: 0644]
libgo/go/exp/ssh/common.go
libgo/go/exp/ssh/messages.go
libgo/go/exp/ssh/server.go
libgo/go/exp/ssh/tcpip.go [new file with mode: 0644]
libgo/go/exp/ssh/transport.go
libgo/go/exp/terminal/shell.go [deleted file]
libgo/go/exp/terminal/terminal.go
libgo/go/exp/terminal/terminal_test.go [moved from libgo/go/exp/terminal/shell_test.go with 96% similarity]
libgo/go/exp/terminal/util.go [new file with mode: 0644]
libgo/go/fmt/fmt_test.go
libgo/go/fmt/print.go
libgo/go/fmt/scan_test.go
libgo/go/go/ast/ast.go
libgo/go/go/ast/filter.go
libgo/go/go/build/build_test.go
libgo/go/go/printer/printer.go
libgo/go/html/doc.go
libgo/go/html/parse.go
libgo/go/html/parse_test.go
libgo/go/html/render.go
libgo/go/html/template/content.go
libgo/go/html/template/escape_test.go
libgo/go/html/template/js.go
libgo/go/html/token.go
libgo/go/image/tiff/buffer.go
libgo/go/io/ioutil/tempfile.go
libgo/go/log/syslog/syslog.go
libgo/go/math/big/int.go
libgo/go/math/big/nat.go
libgo/go/math/big/nat_test.go
libgo/go/math/big/rat.go
libgo/go/math/gamma.go
libgo/go/math/lgamma.go
libgo/go/mime/multipart/formdata.go
libgo/go/mime/type.go
libgo/go/mime/type_test.go
libgo/go/mime/type_unix.go [new file with mode: 0644]
libgo/go/mime/type_windows.go [new file with mode: 0644]
libgo/go/net/cgo_unix.go
libgo/go/net/fd.go
libgo/go/net/fd_linux.go
libgo/go/net/fd_openbsd.go
libgo/go/net/fd_windows.go
libgo/go/net/file.go
libgo/go/net/hosts.go
libgo/go/net/http/cgi/host_test.go
libgo/go/net/http/chunked.go
libgo/go/net/http/chunked_test.go [new file with mode: 0644]
libgo/go/net/http/client_test.go
libgo/go/net/http/fcgi/child.go
libgo/go/net/http/fcgi/fcgi.go
libgo/go/net/http/fcgi/fcgi_test.go
libgo/go/net/http/fs.go
libgo/go/net/http/fs_test.go
libgo/go/net/http/httputil/chunked.go
libgo/go/net/http/httputil/chunked_test.go
libgo/go/net/http/httputil/persist.go
libgo/go/net/http/readrequest_test.go
libgo/go/net/http/request.go
libgo/go/net/http/response_test.go
libgo/go/net/http/serve_test.go
libgo/go/net/http/server.go
libgo/go/net/http/sniff_test.go
libgo/go/net/http/transfer.go
libgo/go/net/http/transport.go
libgo/go/net/http/transport_windows.go
libgo/go/net/interface_bsd.go
libgo/go/net/interface_darwin.go
libgo/go/net/interface_freebsd.go
libgo/go/net/interface_linux.go
libgo/go/net/interface_windows.go
libgo/go/net/ipsock.go
libgo/go/net/ipsock_posix.go
libgo/go/net/lookup_windows.go
libgo/go/net/newpollserver.go
libgo/go/net/pipe.go
libgo/go/net/sendfile_linux.go
libgo/go/net/sendfile_windows.go
libgo/go/net/sock.go
libgo/go/net/tcpsock_posix.go
libgo/go/net/unixsock_posix.go
libgo/go/os/dir_largefile.go
libgo/go/os/dir_regfile.go
libgo/go/os/dir_unix.go
libgo/go/os/env.go
libgo/go/os/env_plan9.go [deleted file]
libgo/go/os/env_unix.go [deleted file]
libgo/go/os/env_windows.go [deleted file]
libgo/go/os/error_plan9.go
libgo/go/os/error_posix.go
libgo/go/os/exec/exec.go
libgo/go/os/exec_plan9.go
libgo/go/os/exec_posix.go
libgo/go/os/exec_unix.go
libgo/go/os/exec_windows.go
libgo/go/os/file.go
libgo/go/os/file_plan9.go
libgo/go/os/file_posix.go
libgo/go/os/file_unix.go
libgo/go/os/os_test.go
libgo/go/os/proc.go
libgo/go/os/stat_plan9.go
libgo/go/os/sys_bsd.go
libgo/go/os/time.go
libgo/go/os/user/lookup_unix.go
libgo/go/reflect/all_test.go
libgo/go/reflect/deepequal.go
libgo/go/reflect/type.go
libgo/go/reflect/value.go
libgo/go/regexp/regexp.go
libgo/go/strconv/decimal.go
libgo/go/strconv/decimal_test.go
libgo/go/strconv/ftoa.go
libgo/go/strconv/ftoa_test.go
libgo/go/strconv/internal_test.go
libgo/go/strings/strings_test.go
libgo/go/sync/mutex.go
libgo/go/syscall/bpf_bsd.go
libgo/go/syscall/env_plan9.go [new file with mode: 0644]
libgo/go/syscall/env_unix.go [new file with mode: 0644]
libgo/go/syscall/env_windows.go [new file with mode: 0644]
libgo/go/syscall/errno.c
libgo/go/syscall/errstr.go
libgo/go/syscall/exec_stubs.go
libgo/go/syscall/exec_unix.go
libgo/go/syscall/exec_windows.go
libgo/go/syscall/libcall_irix.go
libgo/go/syscall/libcall_linux.go
libgo/go/syscall/libcall_posix.go
libgo/go/syscall/libcall_posix_largefile.go
libgo/go/syscall/libcall_posix_regfile.go
libgo/go/syscall/libcall_solaris_386.go
libgo/go/syscall/libcall_solaris_amd64.go
libgo/go/syscall/libcall_solaris_sparc.go
libgo/go/syscall/libcall_solaris_sparc64.go
libgo/go/syscall/libcall_support.go
libgo/go/syscall/libcall_uname.go
libgo/go/syscall/libcall_wait4.go
libgo/go/syscall/libcall_waitpid.go
libgo/go/syscall/lsf_linux.go
libgo/go/syscall/mksyscall.awk
libgo/go/syscall/netlink_linux.go
libgo/go/syscall/route_bsd.go
libgo/go/syscall/route_darwin.go
libgo/go/syscall/route_freebsd.go
libgo/go/syscall/sleep_rtems.go
libgo/go/syscall/sleep_select.go
libgo/go/syscall/sockcmsg_linux.go
libgo/go/syscall/sockcmsg_unix.go
libgo/go/syscall/socket.go
libgo/go/syscall/socket_bsd.go
libgo/go/syscall/socket_irix.go
libgo/go/syscall/socket_linux.go
libgo/go/syscall/socket_solaris.go
libgo/go/syscall/syscall.go
libgo/go/syscall/syscall_unix.go
libgo/go/testing/benchmark.go
libgo/go/testing/example.go
libgo/go/testing/testing.go
libgo/go/text/tabwriter/tabwriter.go
libgo/go/text/template/exec_test.go
libgo/go/text/template/parse.go
libgo/go/text/template/parse/parse.go
libgo/go/text/template/parse/parse_test.go
libgo/go/text/template/parse/set.go
libgo/go/text/template/set.go
libgo/go/time/sleep.go
libgo/go/time/sleep_test.go
libgo/go/time/sys.go
libgo/go/time/sys_plan9.go
libgo/go/time/sys_unix.go
libgo/go/time/sys_windows.go
libgo/go/time/tick.go
libgo/go/time/time.go
libgo/go/time/time_test.go
libgo/go/time/zoneinfo_unix.go
libgo/go/time/zoneinfo_windows.go
libgo/go/websocket/websocket.go
libgo/merge.sh
libgo/mksysinfo.sh
libgo/runtime/go-setenv.c
libgo/runtime/mgc0.c
libgo/runtime/proc.c
libgo/runtime/runtime.c
libgo/runtime/runtime.h
libgo/runtime/thread-linux.c
libgo/runtime/time.goc

index 5e896c008bf4e34bd3213f3a411aff5e3e539963..f62ea21e57c1d9e231bb3e113b023e7a9e95d664 100644 (file)
@@ -1,4 +1,4 @@
-2f4482b89a6b
+b4a91b693374
 
 The first line of this file holds the Mercurial revision number of the
 last merge done from the master library sources.
index cd264e326687eb242d6f4ba21174953be9f21e39..9701bada7cef70e251b192c04cf3b76cd1e1fbc6 100644 (file)
@@ -648,7 +648,8 @@ go_math_files = \
 go_mime_files = \
        go/mime/grammar.go \
        go/mime/mediatype.go \
-       go/mime/type.go
+       go/mime/type.go \
+       go/mime/type_unix.go
 
 if LIBGO_IS_RTEMS
 go_net_fd_os_file = go/net/fd_select.go
@@ -770,7 +771,6 @@ go_os_files = \
        $(go_os_dir_file) \
        go/os/dir.go \
        go/os/env.go \
-       go/os/env_unix.go \
        go/os/error.go \
        go/os/error_posix.go \
        go/os/exec.go \
@@ -1156,6 +1156,7 @@ go_exp_sql_files = \
        go/exp/sql/sql.go
 go_exp_ssh_files = \
        go/exp/ssh/channel.go \
+       go/exp/ssh/cipher.go \
        go/exp/ssh/client.go \
        go/exp/ssh/client_auth.go \
        go/exp/ssh/common.go \
@@ -1164,10 +1165,11 @@ go_exp_ssh_files = \
        go/exp/ssh/server.go \
        go/exp/ssh/server_shell.go \
        go/exp/ssh/session.go \
+       go/exp/ssh/tcpip.go \
        go/exp/ssh/transport.go
 go_exp_terminal_files = \
-       go/exp/terminal/shell.go \
-       go/exp/terminal/terminal.go
+       go/exp/terminal/terminal.go \
+       go/exp/terminal/util.go
 go_exp_types_files = \
        go/exp/types/check.go \
        go/exp/types/const.go \
@@ -1546,6 +1548,7 @@ syscall_netlink_file =
 endif
 
 go_base_syscall_files = \
+       go/syscall/env_unix.go \
        go/syscall/libcall_support.go \
        go/syscall/libcall_posix.go \
        go/syscall/socket.go \
index 11b86509e6f7b055014d5930603d72a81596f568..3d9ed7c1ca0d7905ceb3383532a109a1ed6fda53 100644 (file)
@@ -1032,7 +1032,8 @@ go_math_files = \
 go_mime_files = \
        go/mime/grammar.go \
        go/mime/mediatype.go \
-       go/mime/type.go
+       go/mime/type.go \
+       go/mime/type_unix.go
 
 # By default use select with pipes.  Most systems should have
 # something better.
@@ -1103,7 +1104,6 @@ go_os_files = \
        $(go_os_dir_file) \
        go/os/dir.go \
        go/os/env.go \
-       go/os/env_unix.go \
        go/os/error.go \
        go/os/error_posix.go \
        go/os/exec.go \
@@ -1521,6 +1521,7 @@ go_exp_sql_files = \
 
 go_exp_ssh_files = \
        go/exp/ssh/channel.go \
+       go/exp/ssh/cipher.go \
        go/exp/ssh/client.go \
        go/exp/ssh/client_auth.go \
        go/exp/ssh/common.go \
@@ -1529,11 +1530,12 @@ go_exp_ssh_files = \
        go/exp/ssh/server.go \
        go/exp/ssh/server_shell.go \
        go/exp/ssh/session.go \
+       go/exp/ssh/tcpip.go \
        go/exp/ssh/transport.go
 
 go_exp_terminal_files = \
-       go/exp/terminal/shell.go \
-       go/exp/terminal/terminal.go
+       go/exp/terminal/terminal.go \
+       go/exp/terminal/util.go
 
 go_exp_types_files = \
        go/exp/types/check.go \
@@ -1890,6 +1892,7 @@ go_unicode_utf8_files = \
 # Support for netlink sockets and messages.
 @LIBGO_IS_LINUX_TRUE@syscall_netlink_file = go/syscall/netlink_linux.go
 go_base_syscall_files = \
+       go/syscall/env_unix.go \
        go/syscall/libcall_support.go \
        go/syscall/libcall_posix.go \
        go/syscall/socket.go \
index 1f893951c15bd14c63595d760a421d6556c9cf1d..54029cd40fdd2e76a484344d588a1c68b25561c9 100644 (file)
@@ -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) {
index 5a7aaf364db82d71a5e91ef7177b889d0e5336e5..e81616ca41894e3b3bba5405e72d5a1525269490 100644 (file)
@@ -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
index 9256b1842742a24298ab825c87e214f78c304df4..21a1a4f5808fee29a7fdc28bd19588a8ebcaa4ed 100644 (file)
@@ -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)
                }
index c787a9568b393d1502b3498e7828b9a4bce3c0eb..0ed742c897774af7515f3fad0b41946b0eca42c1 100644 (file)
@@ -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
 }
 
index 3f380fadce2570a180b902d3ae39656f190168a3..488ba6428db63703b1f056d81113c98f3c447470 100644 (file)
@@ -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,
index 154cdf8090eab035b5acfa1ace853e70fedbf617..d249a09b295ee5a237aa1da4df5f0bdc17bdd942 100644 (file)
@@ -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
index 32f05ab68560c6027af38e14b1b5ed3b887aba83..a71894da3200ab92258727682f8344bd1a5f47fd 100644 (file)
@@ -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
index 5ad75eccb502eada84f060a6fb770e8d05731785..28752e73613cd18d33d3ec7340b0cf7bde597214 100644 (file)
@@ -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 }
 
index a5d56d2ebae8d63865e1b7600e0b81bfdcf02967..94e10f0e267cce2ad76ba9f80c85cb4300208eed 100644 (file)
@@ -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 }
 
index 590571d23f643dc3ad9528002e42cd5cc39b5a08..2b2bd4bba6b0e87dbdb1dc7fc2334cf83ce224f4 100644 (file)
@@ -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
 }
index b44ae9897ba2acc8039ac6163a2a6505c799eb21..fc5fe6c65e9cb07633948ee01febce582d6bfd75 100644 (file)
@@ -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)
index f4178e30c58248dcdd1e777eb5dd03b35e6cbe58..b8fa2737f67e77a9c349ea191ac5cf8b75a922c7 100644 (file)
@@ -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 {
index f11232d8ee57ef268bb96df0cac7c6cfe986f20d..5438e749ce8b8713a7955617a4444e3947835e83 100644 (file)
@@ -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
+}
index 87e8f7e428d90e24eb6932fa620233b278bf8b05..e62a9d581b353b438d8289d8d4ce03bd375facad 100644 (file)
@@ -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
                        }
index b8e27a9a5d261899759f324f667a3ab54b04af0b..13073dcee78c453f4788acae5ac99d808929c3aa 100644 (file)
@@ -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
        }
 
index 64d933c2b67eef7a3f58b3d3a4f08968b3da0dc6..3ed05814a3b76163ee0f8774479b46a7d7e5964b 100644 (file)
@@ -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 (file)
index 0000000..f0c5201
--- /dev/null
@@ -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)))
+}
index 41295d2d24142d8eeb8815676dc5338c9453e124..2ea06c50c277985e216ed2eac3d73d498f71ffa4 100644 (file)
@@ -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.
index 179690464b9f9e46cd50a64b92d104cb6f4c767e..2661f410e015e138553a696a18360623e5697a83 100644 (file)
@@ -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
 }
index a0a5995af8ffb1e695264c10067974780be2b271..14d850865a673c3d387cd847ee2720a9503a0bff 100644 (file)
@@ -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)))
 }
index 6c874fadb7a0d7d03d688161d4ae2e64c30b4020..bcb22afde00e2d1a38c4e17fc7eea01594f6303e 100644 (file)
@@ -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) {
index d6b7e8514e63b0bd1d6f7c77875368d516797382..f12436618f299e7cc297712a2168b77f970855bd 100644 (file)
@@ -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 {
index e46cebe9a3da51f5e8901b41dfad61222209e52e..48e281203bead02bd2f197a330c9a0528bd81090 100644 (file)
@@ -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.
index 6a51c342415a33bec30bf2e4ba4ee7e5e7a51432..91a388421d17b40724b5660b214bb3b1866a4b6c 100644 (file)
@@ -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
 }
 
index c8a19974d641df1317c832829ba7929a7a71df9c..17028e2cc388401fec45cecff753b79a7f15403d 100644 (file)
@@ -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")
index 291af7f67dcb0878f8c1fce8322daa9f0ea2619d..c055fdd68c63648194d7165790e23f33efaf8449 100644 (file)
@@ -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
index eb1bb58966eae95ee8f8011dcf1d4669433f5681..d365f6ba190970d0f0124a8ea0208f787a6c0844 100644 (file)
@@ -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 (file)
index 0000000..de4926d
--- /dev/null
@@ -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 (file)
index 0000000..ea27bd8
--- /dev/null
@@ -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)
+               }
+       }
+}
index da45688eee08ca362a471a8c0eed54386006b3ef..24569ad9389bd65d6c026a208606660ecd75d032 100644 (file)
@@ -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 {
index 0089d0c769e33b7702a7324c94dbbb434f0eff67..25f9e21622530b40ef687fcf5133fc3066cd80ad 100644 (file)
@@ -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 (file)
index 0000000..6467f57
--- /dev/null
@@ -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 (file)
index 0000000..1374560
--- /dev/null
@@ -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()
+}
index 273820b6428c62706df848f91f0cce4f83b37a7c..01c55219d47578f2133c43663b5052eb762b503c 100644 (file)
@@ -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
+}
index e24b6398b56fbd57fc349570634b5834e5edf09d..cebb5609db38711e01f8992923e126b4bb9374f5 100644 (file)
@@ -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 {
index 62035d52b7dd6ba7e5539ac497ecfee19440da17..428a747e1e0c89b424d0349d5f6ccde744d2c503 100644 (file)
@@ -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 (file)
index 0000000..859dedc
--- /dev/null
@@ -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")
+}
index 579a9d82de914604a95e918d098a3d9e9fe8c18c..b8cb2c319d85e119495cee900a81993a4a5ffc73 100644 (file)
@@ -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 (file)
index 5c59167..0000000
+++ /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")
-}
index 5732543ffc2772647bf363994cef4f5fa0d5eb91..18d76cd6b902769d709afc54dac26871c6918662 100644 (file)
 // 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
 }
similarity index 96%
rename from libgo/go/exp/terminal/shell_test.go
rename to libgo/go/exp/terminal/terminal_test.go
index 8a76a85d5dcc0c211eb9ab995f21f44024ffb3da..a2197210e2a8d4da5720b2c797afccd21156011d 100644 (file)
@@ -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 (file)
index 0000000..0303567
--- /dev/null
@@ -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
+}
index db83f85f9570c55ee269003b437306647c643336..6370560d0bfa65acfa1b71bc21febb7fecc1494e 100644 (file)
@@ -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]`},
index bfa88d187049ab9d6a88030fe60830f2c6cbdd94..7143e07a36e96f6f21b6a041a377535f5c62f46c 100644 (file)
@@ -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('[')
index d3c39be60714e5a0ae15760d82b62e0bf15e2144..0689bf3b6e4e35f6508962ec64a0dd0b38ea54df 100644 (file)
@@ -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)
                }
        }
 }
index a0aa5ff12049f10677da60d4062b61b5ad4e9953..1485f351c07e115954f9f127b3868822242519ba 100644 (file)
@@ -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 (*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()      {}
+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 (*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()      {}
+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 (*ImportSpec) specNode() {}
-func (*ValueSpec) specNode()  {}
-func (*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 (*BadDecl) declNode()  {}
-func (*GenDecl) declNode()  {}
-func (*FuncDecl) declNode() {}
+func (*BadDecl) declNode()  {}
+func (*GenDecl) declNode()  {}
+func (*FuncDecl) declNode() {}
 
 // ----------------------------------------------------------------------------
 // Files and packages
index d7d4b4b6b6d6e3dfc5620f8cf6050151846406ae..bec235e2f98480c54dc2bf9ae9688b132eb9245e 100644 (file)
@@ -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
                }
        }
index db8bc6c8a591533f3a510cd08a4536db6543357d..e22a49aa3d6179d0b202046f7944da8b901a7300 100644 (file)
@@ -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",
                },
        },
 }
index aba7d93a64bbff874bb94bd87d95d354aa48bdcc..6104c326c665ea7c0cb12419b3521e4c44c5e40f 100644 (file)
@@ -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
                }
index 1bea690c2c8984fa663bb2361be9dc51d71eb0e2..56b194ffb9080c3ec6d77784a47403e9ddb7ce5c 100644 (file)
@@ -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,
index f47d4ea147cb2f6ac1a3f08498f88b44c5c9c284..9b7e934ac343e27b1ac9e6f55d587a421e0b729d 100644 (file)
@@ -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
                }
        }
index 27979225b332a5202dd5159a5f5dadd392158c8e..4f15ae1d554c55eae9a3db4a9708939fc1759468 100644 (file)
@@ -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,
 }
index c815f35f1e1d9e3f6724e386ae2caefcabd19338..92c349fb32c890addd69796b02b03279641b0eff 100644 (file)
@@ -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
                        }
                }
index d720d4ba6895df1e0a48463f38ad02bd76815ada..3fb15a6e93f56e294f169a88c99da5b0dc6b7b1a 100644 (file)
@@ -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
 }
index d8bfa321121020dd8d8e65bce99f56df4c41662c..4af583097bd55fb165e69e3b0fc8af3019cc9b10 100644 (file)
@@ -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
index 68c53e5ca3b549484ae59368c190170ae64497d9..0e632df42201e49661f98d0671069e2b4bcb155e 100644 (file)
@@ -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
index 2c138227b1049ffc738712a677a452e1bd0a19db..9400873e6b8e6b81639d8358700f63910032bda6 100644 (file)
@@ -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
 
index ce350738ed8c1fab617abe48914de9c0f269427a..27533c6047d5579eab29e4aad71db5dc558c0d08 100644 (file)
@@ -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)
index 658ea78bb7c700d52a87070710fe383a68e6328c..71028e226773a40cd393f46b56fdd1aad2851c42 100644 (file)
@@ -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 {
index 26a2f736b174a636e07a6fb5648a474fb4551159..546bc296a5ffd9d4f4526f133dce0fec944b9f9e 100644 (file)
@@ -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)
 }
index 533a97f7495012ff6a147695d19b02c25fa2cd61..35e2e2941832294032ef563298b87ad31b45454f 100644 (file)
@@ -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
index 3fa41e7565f3114a72fcfb0cf0dbe5baecf70d03..eee8ee3f66cc6dadf4f0c1998aa0cb54ed601d0c 100644 (file)
@@ -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
index 041a6c4a255f884163bb8e267d70ba6535252f03..b208646f2f2839c08dc47aae6817a02fffe85988 100644 (file)
@@ -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)
                }
index 3a0add3236361df14a4806a8b2970ef203102ad9..adf412485f69e923575fc83d534dd10be9984828 100644 (file)
@@ -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)
                }
        }
 
index e117158fee2e28822e1abee8803c3117a865f5d0..ae2c0c418ab7b04cb3a03adfa7c2e4cae200eb07 100644 (file)
@@ -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:
index 8f6d7b99fc5e98b82ad262cbb8d058359e40a414..e2bad69dc03d0f8d9fa2245419122f3121f37846 100644 (file)
@@ -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)
index d9982e5b9c8807b03c740a6812f7471a1e5bce9b..ec643c1476fd930230cabb351e6b57d6f13c0da3 100644 (file)
@@ -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
index ce72bb5f7f9461d1bff8998373dbcf8bdcaea37c..e3d968fb81a15b882c1b1dcbd182488595686e41 100644 (file)
@@ -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)
index 976f85343099d6df209b6100ab52017200843455..07e1cd5daecfbfb84896a582fd1c1b3be9eb1705 100644 (file)
@@ -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 (file)
index 0000000..45127ba
--- /dev/null
@@ -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 (file)
index 0000000..7cf2d39
--- /dev/null
@@ -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",
+       }
+}
index 680d3e70b119435562a1bc8f0afacf57eec6981f..1a0f4063c5a7ee5a8f3fcf1890e0cddd935a7d12 100644 (file)
@@ -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))
                }
index 025075de48f3e11600efb7195d55155625d3b2e2..70e04a21c0b5c0cf50f64023771fc80e65d49e33 100644 (file)
@@ -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)
 }
index cce74cd6760147667fc1b9c4feb1c793e266d39b..8e07833882e5a48d88c9158bedaf05b707856297 100644 (file)
@@ -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
                        }
index f61008a2fe1b19955c0d06c12e61c462e578a77e..e52ac356b9fd5b086c3bb38e37fb34b28a04bb50 100644 (file)
@@ -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
                        }
index ce228e91edb358113a17355e1ecdcdc4f98b3014..7a1602371e9c726a178f5fc20cda66523c448d3b 100644 (file)
@@ -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.
index 0ad869dbd57995901e27dc30d106e2f07c843bcb..bf8cd9dae043e75c23daecb601cd85bd30d892f6 100644 (file)
@@ -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)
        }
 
index d75e9e038a6791360b4f1a1cb49c850015726e7c..ddfb074ee8f12a43f119c344cf218f20c6c15feb 100644 (file)
@@ -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
index 2bc913a1696d585fd861e94f93d31b4daaadc42d..e6e85e8db3b0f4db9ae139941990aaa2245af580 100644 (file)
@@ -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")
        }
 }
 
index b012dd18496c8e0f0d5dabccce865bf3d21a63fb..74c41aabd41fd49ad1a63dea3c573617f8cb5e82 100644 (file)
 // 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 (file)
index 0000000..b77ee2f
--- /dev/null
@@ -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)
+       }
+}
index d224380298c86663060c0c27f5b735e4707b471c..57a9dd9574d1a6c201ed635a22c26a460196d038 100644 (file)
@@ -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 {
index 7b563951ccf202a4287b3ff376e40934e61c75d9..529440cbe92a0d7a644e93cdefb9215fb8aba7aa 100644 (file)
@@ -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) {
index 70cf781e228623aa23e904f344e5354030624b6e..d35aa84d229aab920addb06265aa9768f43b1c1d 100644 (file)
@@ -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
 }
 
index e42f8efd65847a9555b35acdc8d8a70bd0a0d9d8..6c7e1a9ce831ff428aa19605e42f74d554a12361 100644 (file)
@@ -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)
+       }
+}
index 5f91ff5cbf659122eb4faa80c213030818e7c20d..5aadac17a23535401049e52dda1e705a300aac33 100644 (file)
@@ -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
        }
index e1a784c1f6d191776824617c1c5b94160bb7e80b..6697189900ed947ddc943ede45420e289057ba97 100644 (file)
@@ -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")
index 34e47c796c19ce5afcd6a88dae29933c91f067aa..69bcc0e816fdbd5432f891a47f4131d2fe79edda 100644 (file)
 // 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
-}
index 258d39b93cbdba259a03394ccf673e4b7aeb38e4..155a32bdf9a2aca3a371e503699cd5f5165ac186 100644 (file)
@@ -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)
index d7b670110c4bcffc1532f889be5791c719d3ed92..1266bd3ad22eb98414956543c5211b8cfacd234c 100644 (file)
@@ -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
index 2219d43316593b73439f5544de48a67e6d98b1fb..c64fff6109f2270564b11878fce42505d09129f2 100644 (file)
@@ -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",
index 4410ca1d11ceec8c9bc925a8c3b984556771bcba..66178490e37b80dfb8e427ab30eafe39b2539d91 100644 (file)
@@ -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)
index be717aa83c3c586b9ca0f38de6dabdfe00ee67c9..e5d01698e5504bdd1949bc1758661be6a4eeae48 100644 (file)
@@ -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")
index e278396091d590c98575de12e305cb26b07943bd..97a0b139e392796aa9e03b8f725156905221e856 100644 (file)
@@ -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 {
index 8c4889436f1c6006dd8d52f31bf00305719de9f6..7221d2508bb4e4856e8f61080160190fbf295f5e 100644 (file)
@@ -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
index a414e6420db88c39058cfd6b2f59d1faeb6214b7..86744eeb56b762f22e517e6ece559ff023baf704 100644 (file)
@@ -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()
+}
index 2670d77ef00ad864ccec45efe8e66f2f22e7bb22..d25c8fcde42b25c8b781e3f352bd1f35f89c4118 100644 (file)
@@ -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
index da5244b2c12ed0e7ea18b9f4015733069bc543a2..e622e41f0a2de014b8ee9e3a95b5082cab1c05d2 100644 (file)
@@ -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 {
index 2a20d2224ae47c692fba2c34cd022287ac906381..c9ef2c2ab6ea511219a05ce897cef116470ef461 100644 (file)
@@ -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
index b026e01104db077fd79fecd53a79aefe22ca0aec..e896d43c321f29f8f7c1d05180747369e6a2d3e3 100644 (file)
@@ -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)
        }
 
index 1472afb8846fa0cd3e62b056e5f8bd7ee6a9554f..2da447adc8438ed4ee6fb997d3a6dbbdc02bb321 100644 (file)
@@ -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)
        }
 
index b0274f68d7513d16a5ddc8c0b572f4eaabb36304..a12877e251b0cb35950f78dae0791acf8d4bf8ad 100644 (file)
@@ -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)
        }
 
index cd0339d61bd8983d4022d1cf0590ef0714870200..96db7186af552d6d53cbb8af04a6aa1980383239 100644 (file)
@@ -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))...)
index a1c8d95161ce294d028947b98e856d3bd85e1377..2ed66cdce377a58e489f4cf4a5ded52419e2cfa9 100644 (file)
@@ -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]))
index 716454d8a98db0cbcfcc6862f5fe25178e141821..9234f5aff65127391f39593980d13a0f05c29dc0 100644 (file)
@@ -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
                        }
index d5b8f2189c4401afb6e40b03e823608b9f5cb2e6..f0ca7dad3457b485d208bf2e0e4437c7c3694b21 100644 (file)
@@ -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
index 61d8a8871e1d4ac80d23fb419f84c3090637c73a..020871b46d6c88fd98f79b14ddf17e10e2f169af 100644 (file)
@@ -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)
index 9ad6f7ba2768232ba7e6eb23b47951fee213d929..035df4a6ff141864f5bf9d5c5b5b6cc2975eda90 100644 (file)
@@ -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()
index b99e6e658def4e8834d6c3f861a08df91ea55520..0ce7ccb9d7b1af1144adf5d8d33cfbfe5a86578e 100644 (file)
@@ -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 (
index 36c75785789b24482a302010b2682cd61f036f0c..350abe451f37854b1d26889ca5a243010e51f251 100644 (file)
@@ -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
                }
        }
index 0b31572771c8303799cd5a7deb4d3468545af721..ee7ff8b98c2d9849f4905610d22a13d3955a9c81 100644 (file)
@@ -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)
 }
 
index d9df02cd63fd393632d3189cd5386da39afcb1c6..33f11f219c9f2a8ca2d79f15ff0844be571f4c77 100644 (file)
@@ -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
                }
        }
 
index a726b45c15a81a689df674b4295b850f7c66b22b..44890ba66bb53391236128b78914ba8765efcdd2 100644 (file)
@@ -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
index 6ba692e508371a6a723b09ce77fa346afd0fce3e..929f6409a4f0836fe18c719b36b0b133b4de7cb7 100644 (file)
@@ -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
 }
index c723ec92400285e64da553a2d30731b48e0d90e2..d6b4239610ec22a8dda6a43db5c129a7f815006b 100644 (file)
@@ -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")
index 22fb5febbb2d3d440b2afd02c577f14910667182..7effdf7851a84daf5a7a858f1fc218fe868afa78 100644 (file)
@@ -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")
index a16bcf63f41b4abe8291f2f5992baaab5c2bbd3e..e4dff835d89975033f728f3aa105465382cf6288 100644 (file)
@@ -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 {
index 4844fa3e26d61280b500c1deaa567f781016730e..7e3f52502e54ef93afec26e75991de666e19c17c 100644 (file)
@@ -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 (file)
index 9757aa9..0000000
+++ /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 (file)
index 01fd9d4..0000000
+++ /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 (file)
index 4e90385..0000000
+++ /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)[:]))
-       }
-}
index e08707078eccfcfe2926c91ef917c3c2249f33b7..8f005efbe056fa38468bb43e9d01284ff6e9e9c6 100644 (file)
@@ -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 }
index c3d7942506251c0c690451691cc5c7bdc259465f..dbe1b9a8d5eeb37cd7b7a6bc32796ca78586dc26 100644 (file)
@@ -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}
 }
index ebdfd54a73411da70522efaa9d14e54c61900f43..4c95c1b0dac5a750592365eb4311895e378f9e98 100644 (file)
@@ -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.
index a1a335359dc7e581f696dc73fa36b9f80bbbb74e..9a0db6dd3efbdcf0c71dccaf7ae499df2a915e9b 100644 (file)
@@ -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)
                }
 
index 12b44e5f33bfef63c56da403cd303ac313f80def..8b08eebd0daf0fb195b6f237ec1aa0d26d135839 100644 (file)
@@ -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
 }
index 242bda702c605d95a9de737285f40ddb33671d97..3dcac414c5ab41cba7b14b23c36eac96239ef343 100644 (file)
@@ -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
 }
index 866757e312961a7552df9ded3a7fcddf7b207e1c..c4c9dcfe8292d72418c816ec3810bb5b2b53fa33 100644 (file)
@@ -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)[:]))
+       }
+}
index 0f3b2db7ea2484ef480882f557a5d56cc3b6590a..386afb889b2c9c3e8e4225e0a013a530d6fe14d8 100644 (file)
@@ -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
 }
index 42332e157ef4d57f3fa29a334a0133263522f9bc..42fefa96fe8ed4e0c0d61a439063570aaf06069a 100644 (file)
@@ -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"
+}
index c937b6d62666678d49be544bf6ac2e25c20f720c..c80d3df5e50a5ffc64783913f41664b76f07c834 100644 (file)
@@ -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
 }
index a7ccb337eb535fdaff0f7ffd2767f9b7c064ce0f..0bf31ecb9a74258abf8a4b1768ea58e3421c114c 100644 (file)
@@ -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
+}
index 1d6d872d5c7bdb7eea40731a55a7a88710bdf09e..170f7331c6e4547f1229dbbac220c983b5392f26 100644 (file)
@@ -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
index d21f849f21085d12106f0278507f739be2faf6e2..61545f4456a316aa8abec19d2571d299409a2a01 100644 (file)
@@ -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() }
index 8df9e580cc45aff39f50fa4311375538326d926e..e4a1dbbaea394f6af4a81edeed5c296ae9df4148 100644 (file)
@@ -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
index 67133a1898b5062ef9427d2c0fb86207eb8e6289..c6a6de5c816f6d39826afa182610022a4a36ab2c 100644 (file)
@@ -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
 }
index a4678ee2a169a57b0ed0c54bc853cd66ac737449..eb564e57a6cc05baf2171bb130cd08e931e653f7 100644 (file)
@@ -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
index ba4e1ac799155e25e1b44c25236d609f610720bc..89886cb03cf2c0f9d0f5628eab30e08abb9b1441 100644 (file)
@@ -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)
index 7c1022ecb4832b5bb508c16b4daa3ca3f63be508..cf31d1ba39d326c253b3a6020a1788e8240db840 100644 (file)
@@ -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)
        }
index 63c28fe2024d37c7fd16a711c7741dd62b46a526..df5ec0a6099576a27ecc83282ed3e346a8ebb015 100644 (file)
@@ -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
                }
index 9be7f83087573711cf73e9b758919d26a1194c84..07cc0f5ba401be24e205854b1c6aa760f249ecf3 100644 (file)
@@ -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 {
index dbdfa09242faa1a2bdd8e0a6e515d665a78c942b..b57ed462c84cb7ad12923355a02394e3c91366ba 100644 (file)
@@ -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("reflectMakeSlice 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("reflectMakeChan 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("reflectMakeMap 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{}
+}
index b906076f9eb270a11237ac444b7a478620934916..59f3be39d294d56ab19ca4c6bb7a4b01215ceeb9 100644 (file)
@@ -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.
index f572ea4a22d5056e07ad0b22cd867180f9866a78..541553097bbb3a2e9fcb1449bc2cc34710693277 100644 (file)
@@ -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.
index deb2e02f6108478e9f64270faf0abdb775d24222..13a127f5b2cfc9a1123a86d2711132ca69555891 100644 (file)
@@ -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)
index 07fe806b97dec2cdf3ea724a5ef594ec26f7546c..8342b6abe79494db82e085a377396e3479518c6b 100644 (file)
@@ -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
index 6d361a138efe81638a69c247ed51a1afad219899..8bac5da452671e3047bfe3210a500129e51e1f89 100644 (file)
@@ -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)
+       }
+}
index 9a7f4f0867c5d53f79fe007e4364491ec4d186a9..d0fa80edfb6f9a7f2a66535405111c313ef863ce 100644 (file)
@@ -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
index 304d69a19d70f09cfb0d652fedac3d750eb614f2..96207f5a2da6f995938dab15be67e5806023a4c2 100644 (file)
@@ -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)
                }
index 2d46c89948fe9c3e25633399c68769ad8bdc8ee6..4fc02743c6e717b19903ee99867f7d7cafba375b 100644 (file)
@@ -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 (
index 06a2953e7fed9f989f5077ee78331b620c63065f..f94b7233b6716d66a5be7a6d19f2cd374c2a447d 100644 (file)
@@ -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 (file)
index 0000000..5185733
--- /dev/null
@@ -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 (file)
index 0000000..df25909
--- /dev/null
@@ -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 (file)
index 0000000..8308f10
--- /dev/null
@@ -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
+}
index 854b5aaec28465054ba50c9acb3e52d96eca3232..8e57811151a5e3cea00c3e6eb1997ce5d2c6847e 100644 (file)
@@ -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;
 }
index d9f3fe82eb47101fc6cfe3e3bd67cb55156e7bf7..5ef10da1fd4d47f8f38c0dd18498c65ae5d4d7e7 100644 (file)
@@ -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++
index 02b9ec34cf3bd89e948aada9430636c21b3aeb8a..74b0af597e8d1c4edc78be923219becc7f317d03 100644 (file)
@@ -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
 }
index 60e9770ce23a186bd3d07260e4dcb6518ad76ec8..c9814b7050efcccf6209c729f0c6fbef7192e366 100644 (file)
@@ -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)
 }
index e8b540ad1603e6e247adf1aecfd3e59edc967dd7..2826e2f35a6ccdc0f1c3e7ae0475f8274a476da5 100644 (file)
@@ -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
 }
index ae4535597138e9c95de1abf0ac82e405e21b92c4..69e0db264bdaad9ed050e17893c8e4593fb54e2c 100644 (file)
@@ -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
index 3948e51ae285af7a41de9bc5cd3146bad26b4d37..79f5d48ae8b5df08056dcbf5ed4eb8e75d2c56c2 100644 (file)
@@ -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
index 87ed4e628fd9e9a5a45f438a2b853ef0bce43e66..d90e595dba36bf966434912a6c14fa97fbd27d38 100644 (file)
@@ -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
index acfafecc58171f9f5eb5b24a4fa75fcd10ea4e30..e898648157dfbcf3f6436b1fbbf406b704141de8 100644 (file)
@@ -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
index b71da0ceb48f1d9cad1ab1f0d9c71eecef4661ce..97167013a182d0cdb4ed4158b8ff4714cf5fb3db 100644 (file)
@@ -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
index 9c4e966f1ae9ca99ae8a3b08c1222655f8536045..e94deecf8cddbc1fee5257444625e2d190e21bca 100644 (file)
@@ -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
index f0d335dbb67792a97ee19210ed3e1a6a222dc864..69b11ba5ee64810c5785a64d20d40b8a37d571d3 100644 (file)
@@ -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
 }
index ae4535597138e9c95de1abf0ac82e405e21b92c4..69e0db264bdaad9ed050e17893c8e4593fb54e2c 100644 (file)
@@ -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
index f0d335dbb67792a97ee19210ed3e1a6a222dc864..69b11ba5ee64810c5785a64d20d40b8a37d571d3 100644 (file)
@@ -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
 }
index daed8073caf5f0664c6319add8c921cd58f57969..7449a0adf79d545ed5bdd7cfa2268596cd3a6389 100644 (file)
@@ -8,5 +8,5 @@ package syscall
 
 func entersyscall()
 func exitsyscall()
-func GetErrno() int
-func SetErrno(int)
+func GetErrno() Errno
+func SetErrno(Errno)
index e4c32b12d6adabf7228dbc59014551cf2f151d62..519e6dc25d07c7f8bbe46239b4f866f88997ed5f 100644 (file)
@@ -4,5 +4,5 @@
 
 package syscall
 
-//sysnb        Uname(buf *Utsname) (errno int)
+//sysnb        Uname(buf *Utsname) (err error)
 //uname(buf *Utsname) int
index 7a63bc71e97cf12378a6255917461e068ef372c6..578686926f34373df8925025f1bcfa94c0d00734 100644 (file)
@@ -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)
        }
index 014446307e320102bff13c33996caa02a75a48b8..1c476d829d0489c9950e8e0246efdfe8afa21510 100644 (file)
@@ -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)
        }
index 0976688b9e713d084d1f2167876bcc1add34fc90..05d653b4aa0cf56c2a3d84a56076488a7af280b5 100644 (file)
@@ -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))
 }
index 49828d94ce35ebbef1a77acb2366b38d7470d07f..b02989cc323e7391777725d84cd56e174b8f2ebe 100644 (file)
@@ -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)
index 4ee78d62f25706597fa6a38b52f11d718d1d50ae..8683bb3dacb4dfa159f7e2fc23c27ff3c4da8f8b 100644 (file)
@@ -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
 }
index f6b124b64e474fe56a63785c4328900345eea46b..bc4c15e950bfa8c48bb9065d86393f4525df0c97 100644 (file)
@@ -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
 }
index 9d3a701daba859e7fbcdb821b4848bc32091cacc..410e70a138a9ffaed192a94f2ea53da2f1af6c5a 100644 (file)
@@ -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)
index 0d61d08b08cfbaf186ed69d4a41a60760c4fc4db..094e17044dbb1fe8069a3de917b797f354389711 100644 (file)
@@ -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)
index 8992eb53c3e1baa6f78d32d74dcf9ed2cd475301..9d72203e8eff82b14c455a89c8c9930850488a03 100644 (file)
@@ -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
 }
index 3ebaf58f96994606dc346222864a699b3b927611..533f554da05387885f969e276b568902e1408a1d 100644 (file)
@@ -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;
 }
index b025ca52101b9717cb978813ce71800b0bf02598..0b4caa1d0557fbfa643bac5154b6a71624039460 100644 (file)
@@ -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
 }
index c9872aeba31ed35adfc24699b69c0649e1e10fa7..84c1383d7e28e1e65bc11ee876d7df6932adedf7 100644 (file)
@@ -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
 }
index e0218ba359d001744741ca2d647e2925a36a74a2..005fd843486d15e351ab6bddc39d8c3293ae8e72 100644 (file)
@@ -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) {
index 735baf98684292d309841f037a48366a24f58fe1..be55991595164c4fa2037827191e3ce8f0a9c31e 100644 (file)
@@ -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
 }
index 8bd55b8b4d9001f2797ef703e05182b365084828..c1fdc656ab0916e8ed32ac32b513910da0b2fabf 100644 (file)
@@ -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
 }
index 49aac87bb7a0836dc90cd0a2f075f41b381848f5..212e0b2d4181ffa466c163e04f5d9ee7134d82b2 100644 (file)
@@ -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
index 0c3e6c9724eb510f18ee71a3e67b2e01776f2399..0a03465a3388821217b7378fae836a55ca241369 100644 (file)
@@ -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
 }
index a802ba0bbf28a73a42a12e66a3bd84ddef80cc94..ad9df6cff9859c0dc3ca4518d3e3e0789729dfa6 100644 (file)
@@ -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"
index c734b2cf06aad8ef17ffb6f729ee860950a717c7..899a65ca9b441083156c2d5e039df4245b2277b5 100644 (file)
@@ -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
+}
index df4c4a1a29be16ccf8f934331c2cd6e4334eb30e..4f049a31f758d5c3ae1b8713050bbfce25e78f80 100644 (file)
@@ -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)
                        }
                }
        }
index 5b3e322b593fc640d5bc5792673051814c369c0b..3b026ee66e00787d78f58eb94c3f29a15b181023 100644 (file)
@@ -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)
                }
        }
 
index 5869642c7e1f1ebb6bc707edbd8dbc1cc35089aa..08443a31259d702db23e4ea04e4d3ec1eff88808 100644 (file)
@@ -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)
index c136ca2a175c060aae4f0942c79d3052d82c011c..201a685c6305656b8319e19bae17eb7e1072d66b 100644 (file)
@@ -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})
index 57216676410907aac6356e76387760d5063ee6b4..67b9416cd7673b87de38de93a7792d3d5efd0350 100644 (file)
@@ -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
index fa562141c29f28852cdd2e274f748bc633241563..7075f2ac20e61d0d016da087cb17f3f683088b21 100644 (file)
@@ -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
 }
index 1b6ab3af4f05de9af4715daa271c0e750d116da2..e906ee83aacb5a14b38ec8bbaf72eaba12ebf0d2 100644 (file)
@@ -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)
                }
index f05f6e3874cc86c69ba5707fbba6105a3d7f22d6..5c10086cc7c2cf765944658a6e935f3541ac9ae2 100644 (file)
@@ -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)
index d363eeff080308fcd6d31f771dcb2dab7a7bc4af..55f3ceb3d515ae432424f73df428238e058e823e 100644 (file)
@@ -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
 }
index 747cc7802b434262de99915af1241dea8c2fcfb7..48417044e7755799bd92e8439357bc18f3f0cbcf 100644 (file)
@@ -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
index 314622d0dc9997f48ac629ad228215c1dc0a522e..967fca09b99641e04bec2f1b067681c37570a8fa 100644 (file)
@@ -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())()
 }
index 0662e3359cf4c8b58ff0dba034de905c445ac748..9171da3af1cec59bea2d1dbf3f58060668d3c31a 100644 (file)
@@ -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)
index ca1d334a5b7aafa87d61bb322f070e012ec2ec0d..a5e529b814a936af7150660602debafbd449b52f 100644 (file)
@@ -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)
index a630b3ee03023452803800a9db8cf888100e105b..e58fb519ea32e5c22065a2a551213d00e2e6cdd4 100644 (file)
@@ -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
index 17a6a2d63e096f73adb29a1b02b93fd070b93f56..3d313228b01970ad6cd0eb038a527d444255f433 100644 (file)
@@ -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)
index f9d6e89281c8f3f130094a202d12d3809b90f06f..8c7242f4275cb7b5718a97b81545c9f34c00de7d 100644 (file)
@@ -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() {
 }
index 92f9eb893e4e68e4578021e7033ef066cd1db017..95941a1e8196a6e85816d2b888364d6e650dbb6b 100644 (file)
 
 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
+}
index 859b31672780ff17f4168670c73d4a50fdd20ea5..e11d17731b4fe3dd5c6b400e1ff14c840fd141b1 100644 (file)
@@ -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
+}
index 8b373a13bc29a3d4f53e89bb655b0f021c0c0549..01b8bea4aad495a6e933a5f9f62fc377f29896b8 100644 (file)
@@ -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()
index 0dc423531366af18b7674dd07b311bdde0fdb007..b552e589aa947a08a97d0fbb9dcadb458330ff79 100644 (file)
@@ -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() {
index ba152e0882a2995f64791c7e8fb5fdce1b623482..995fd44dc063a5a7f6cf58d10ecf26750e43ccf2 100644 (file)
@@ -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
        }
index 1e4036ce391d101f6363ebb878fd992a23b7a000..df4416e22ed9e999ffe5c4a3bca6bc2bc2f2ca91 100644 (file)
@@ -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.
index e6d7898dfe128e18c9501667290ab2213a85ac89..496abe53ad54eca290a4feb7cf9c9f730697c842 100755 (executable)
@@ -137,9 +137,6 @@ merge_c() {
 }
 
 (cd ${NEWDIR}/src/pkg && find . -name '*.go' -print) | while read f; do
-  if test `dirname $f` = "./syscall"; then
-    continue
-  fi
   oldfile=${OLDDIR}/src/pkg/$f
   newfile=${NEWDIR}/src/pkg/$f
   libgofile=go/$f
index e493ef072c1590aa131b7949af89636ae0a11275..6d8575c92625af99d483131feeec0eca90e776c5 100755 (executable)
@@ -120,9 +120,10 @@ grep -v '^// ' gen-sysinfo.go | \
       -e 's/\([^a-zA-Z0-9_]\)_timestruc_t\([^a-zA-Z0-9_]\)/\1Timestruc\2/g' \
     >> ${OUT}
 
-# The errno constants.
-grep '^const _E' gen-sysinfo.go | \
-  sed -e 's/^\(const \)_\(E[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
+# The errno constants.  These get type Errno.
+echo '#include <errno.h>' | ${CC} -x c - -E -dM | \
+  egrep '#define E[A-Z0-9_]+ ' | \
+  sed -e 's/^#define \(E[A-Z0-9_]*\) .*$/const \1 = Errno(_\1)/' >> ${OUT}
 
 # The O_xxx flags.
 egrep '^const _(O|F|FD)_' gen-sysinfo.go | \
@@ -191,8 +192,10 @@ fi
 grep '^const __PC' gen-sysinfo.go |
   sed -e 's/^\(const \)__\(PC[^= ]*\)\(.*\)$/\1\2 = __\2/' >> ${OUT}
 
-# The epoll constants were picked up by the errno constants, but we
-# need to be sure the EPOLLRDHUP is defined.
+# epoll constants.
+grep '^const _EPOLL' gen-sysinfo.go |
+  sed -e 's/^\(const \)_\(EPOLL[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
+# Make sure EPOLLRDHUP is defined.
 if ! grep '^const EPOLLRDHUP' ${OUT} >/dev/null 2>&1; then
   echo "const EPOLLRDHUP = 0x2000" >> ${OUT}
 fi
@@ -498,9 +501,11 @@ grep '^type _addrinfo ' gen-sysinfo.go | \
       -e 's/ ai_/ Ai_/g' \
     >> ${OUT}
 
-# The addrinfo flags.
+# The addrinfo flags and errors.
 grep '^const _AI_' gen-sysinfo.go | \
   sed -e 's/^\(const \)_\(AI_[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
+grep '^const _EAI_' gen-sysinfo.go | \
+  sed -e 's/^\(const \)_\(EAI_[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
 
 # The passwd struct.
 grep '^type _passwd ' gen-sysinfo.go | \
@@ -644,17 +649,18 @@ grep '^type _termios ' gen-sysinfo.go | \
       -e 's/c_ospeed/Ospeed/' \
     >> ${OUT}
 
-# The termios constants.  The ones starting with 'E' were picked up above.
+# The termios constants.
 for n in IGNBRK BRKINT IGNPAR PARMRK INPCK ISTRIP INLCR IGNCR ICRNL IUCLC \
     IXON IXANY IXOFF IMAXBEL IUTF8 OPOST OLCUC ONLCR OCRNL ONOCR ONLRET \
     OFILL OFDEL NLDLY NL0 NL1 CRDLY CR0 CR1 CR2 CR3 TABDLY BSDLY VTDLY \
     FFDLY CBAUD CBAUDEX CSIZE CSTOPB CREAD PARENB PARODD HUPCL CLOCAL \
-    LOBLK CIBAUD CMSPAR CRTSCTS ISIG ICANON XCASE DEFECHK FLUSHO NOFLSH \
-    TOSTOP PENDIN IEXTEN VINTR VQUIT VERASE VKILL VEOF VMIN VEOL VTIME VEOL2 \
-    VSWTCH VSTART VSTOP VSUSP VDSUSP VLNEXT VWERASE VREPRINT VDISCARD VSTATUS \
-    TCSANOW TCSADRAIN, TCSAFLUSH TCIFLUSH TCOFLUSH TCIOFLUSH TCOOFF TCOON \
-    TCIOFF TCION B0 B50 B75 B110 B134 B150 B200 B300 B600 B1200 B1800 B2400 \
-    B4800 B9600 B19200 B38400 B57600 B115200 B230400; do
+    LOBLK CIBAUD CMSPAR CRTSCTS ISIG ICANON XCASE ECHO ECHOE ECHOK ECHONL \
+    ECHOCTL ECHOPRT ECHOKE DEFECHO FLUSHO NOFLSH TOSTOP PENDIN IEXTEN VINTR \
+    VQUIT VERASE VKILL VEOF VMIN VEOL VTIME VEOL2 VSWTCH VSTART VSTOP VSUSP \
+    VDSUSP VLNEXT VWERASE VREPRINT VDISCARD VSTATUS TCSANOW TCSADRAIN \
+    TCSAFLUSH TCIFLUSH TCOFLUSH TCIOFLUSH TCOOFF TCOON TCIOFF TCION B0 B50 \
+    B75 B110 B134 B150 B200 B300 B600 B1200 B1800 B2400 B4800 B9600 B19200 \
+    B38400 B57600 B115200 B230400; do
 
     grep "^const _$n " gen-sysinfo.go | \
        sed -e 's/^\(const \)_\([^=]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT}
index 9c93f52668e058481df4d5847a59ff081cd6d4f1..78717f4705ab383281dde0a4f67568392fc5bc60 100644 (file)
 #include "go-alloc.h"
 #include "go-string.h"
 
-/* Set the C environment from Go.  This is called by os.Setenv.  */
+/* Set the C environment from Go.  This is called by syscall.Setenv.  */
 
 void setenv_c (struct __go_string, struct __go_string)
-  __asm__ ("libgo_os.os.setenv_c");
+  __asm__ ("libgo_syscall.syscall.setenv_c");
 
 void
 setenv_c (struct __go_string k, struct __go_string v)
index 0f1cb49e40f4addf83c17ba16c76cfbfb34c9662..c4ab1454c5bf8ec5e223220d682b3d1de1c2e7d8 100644 (file)
@@ -741,6 +741,7 @@ mark(void (*scan)(byte*, int64))
        scan((byte*)&runtime_allg, sizeof runtime_allg);
        scan((byte*)&runtime_allm, sizeof runtime_allm);
        runtime_MProf_Mark(scan);
+       runtime_time_scan(scan);
 
        // mark stacks
        for(gp=runtime_allg; gp!=nil; gp=gp->alllink) {
index 88831d41a67df179255d6463f344d297415e52e2..34566fbf9a0fc5d6817b9ac9ca195c506d5af6bc 100644 (file)
@@ -42,7 +42,6 @@ extern void *__splitstack_find(void *, void *, size_t *, void **, void **,
 #endif
 
 static void schedule(G*);
-static M *startm(void);
 
 typedef struct Sched Sched;
 
@@ -128,7 +127,7 @@ struct Sched {
        volatile uint32 atomic; // atomic scheduling word (see below)
 
        int32 profilehz;        // cpu profiling rate
-       
+
        bool init;  // running initialization
        bool lockmain;  // init called runtime.LockOSThread
 
@@ -826,7 +825,7 @@ runtime_starttheworld(bool extra)
                // but m is not running a specific goroutine,
                // so set the helpgc flag as a signal to m's
                // first schedule(nil) to mcpu-- and grunning--.
-               m = startm();
+               m = runtime_newm();
                m->helpgc = 1;
                runtime_sched.grunning++;
        }
@@ -876,8 +875,6 @@ struct CgoThreadStart
 };
 
 // Kick off new m's as needed (up to mcpumax).
-// There are already `other' other cpus that will
-// start looking for goroutines shortly.
 // Sched is locked.
 static void
 matchmg(void)
@@ -895,13 +892,14 @@ matchmg(void)
 
                // Find the m that will run gp.
                if((mp = mget(gp)) == nil)
-                       mp = startm();
+                       mp = runtime_newm();
                mnextg(mp, gp);
        }
 }
 
-static M*
-startm(void)
+// Create a new m.  It will start off with a call to runtime_mstart.
+M*
+runtime_newm(void)
 {
        M *m;
        pthread_attr_t attr;
@@ -1135,6 +1133,7 @@ runtime_exitsyscall(void)
        runtime_memclr(gp->gcregs, sizeof gp->gcregs);
 }
 
+// Allocate a new g, with a stack big enough for stacksize bytes.
 G*
 runtime_malg(int32 stacksize, byte** ret_stack, size_t* ret_stacksize)
 {
@@ -1283,6 +1282,7 @@ runtime_Gosched(void)
        runtime_gosched();
 }
 
+// Implementation of runtime.GOMAXPROCS.
 // delete when scheduler is stronger
 int32
 runtime_gomaxprocsfunc(int32 n)
@@ -1390,6 +1390,7 @@ static struct {
        uintptr pcbuf[100];
 } prof;
 
+// Called if we receive a SIGPROF signal.
 void
 runtime_sigprof(uint8 *pc __attribute__ ((unused)),
                uint8 *sp __attribute__ ((unused)),
@@ -1412,6 +1413,7 @@ runtime_sigprof(uint8 *pc __attribute__ ((unused)),
        runtime_unlock(&prof);
 }
 
+// Arrange to call fn with a traceback hz times a second.
 void
 runtime_setcpuprofilerate(void (*fn)(uintptr*, int32), int32 hz)
 {
index 8e4433b0d6c911fd291e627566c3b5aeacc49150..ec96f5b615f711247bf2107cb52e8b3dc8df828c 100644 (file)
@@ -87,7 +87,7 @@ static int32  argc;
 static byte**  argv;
 
 extern Slice os_Args asm ("libgo_os.os.Args");
-extern Slice os_Envs asm ("libgo_os.os.Envs");
+extern Slice syscall_Envs asm ("libgo_syscall.syscall.Envs");
 
 void
 runtime_args(int32 c, byte **v)
@@ -126,9 +126,9 @@ runtime_goenvs(void)
        s = runtime_malloc(n*sizeof s[0]);
        for(i=0; i<n; i++)
                s[i] = runtime_gostringnocopy(argv[argc+1+i]);
-       os_Envs.__values = (void*)s;
-       os_Envs.__count = n;
-       os_Envs.__capacity = n;
+       syscall_Envs.__values = (void*)s;
+       syscall_Envs.__count = n;
+       syscall_Envs.__capacity = n;
 }
 
 const byte*
@@ -141,8 +141,8 @@ runtime_getenv(const char *s)
 
        bs = (const byte*)s;
        len = runtime_findnull(bs);
-       envv = (String*)os_Envs.__values;
-       envc = os_Envs.__count;
+       envv = (String*)syscall_Envs.__values;
+       envc = syscall_Envs.__count;
        for(i=0; i<envc; i++){
                if(envv[i].__length <= len)
                        continue;
index 0044319709549df46308c8f6d08a8815bf516824..1c7ede927222f7878f02c5610deb1a56d0a48c0c 100644 (file)
@@ -56,6 +56,8 @@ typedef       union   Note            Note;
 typedef        struct  MCache          MCache;
 typedef struct FixAlloc        FixAlloc;
 typedef        struct  Hchan           Hchan;
+typedef        struct  Timers          Timers;
+typedef        struct  Timer           Timer;
 
 typedef        struct  __go_open_array         Slice;
 typedef        struct  __go_string             String;
@@ -190,6 +192,38 @@ enum {
 };
 #endif
 
+struct Timers
+{
+       Lock;
+       G       *timerproc;
+       bool            sleeping;
+       bool            rescheduling;
+       Note    waitnote;
+       Timer   **t;
+       int32   len;
+       int32   cap;
+};
+
+// Package time knows the layout of this structure.
+// If this struct changes, adjust ../time/sleep.go:/runtimeTimer.
+struct Timer
+{
+       int32   i;              // heap index
+
+       // Timer wakes up at when, and then at when+period, ... (period > 0 only)
+       // each time calling f(now, arg) in the timer goroutine, so f must be
+       // a well-behaved function and not block.
+       int64   when;
+       int64   period;
+       void    (*f)(int64, Eface);
+       Eface   arg;
+};
+
+/*
+ * defined macros
+ *    you need super-gopher-guru privilege
+ *    to add this list.
+ */
 #define        nelem(x)        (sizeof(x)/sizeof((x)[0]))
 #define        nil             ((void*)0)
 #define USED(v)                ((void) v)
@@ -229,6 +263,8 @@ G*  runtime_malg(int32, byte**, size_t*);
 void   runtime_minit(void);
 void   runtime_mallocinit(void);
 void   runtime_gosched(void);
+void   runtime_tsleep(int64);
+M*     runtime_newm(void);
 void   runtime_goexit(void);
 void   runtime_entersyscall(void) __asm__("libgo_syscall.syscall.entersyscall");
 void   runtime_exitsyscall(void) __asm__("libgo_syscall.syscall.exitsyscall");
@@ -341,3 +377,5 @@ void reflect_call(const struct __go_func_type *, const void *, _Bool, _Bool,
 #ifdef __rtems__
 void __wrap_rtems_task_variable_add(void **);
 #endif
+
+void   runtime_time_scan(void (*)(byte*, int64));
index c08cc0dba2950b9ea16d1df4757d46d3bcff19fd..a0ee36006500c0ddc1739fff603f613dca02c443 100644 (file)
@@ -30,7 +30,7 @@ runtime_futexsleep(uint32 *addr, uint32 val, int64 ns)
        else {
                ts.tv_sec = ns/1000000000LL;
                ts.tv_nsec = ns%1000000000LL;
-               // Avoid overflowdefs
+               // Avoid overflow
                if(ts.tv_sec > 1<<30)
                        ts.tv_sec = 1<<30;
                tsp = &ts;
index f5a412a710f48771ce53d93bbb3fe39d812c8076..93b896ed0d2eb85e2a15fcb1b0d81e393a768d95 100644 (file)
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Runtime implementations to help package time.
+// Time-related runtime and pieces of package time.
 
 package time
 
 #include "runtime.h"
+#include "defs.h"
+#include "arch.h"
+#include "malloc.h"
 
+static Timers timers;
+static void addtimer(Timer*);
+static bool deltimer(Timer*);
+
+// Package time APIs.
+// Godoc uses the comments in package time, not these.
+
+// Nanoseconds returns the current time in nanoseconds.
 func Nanoseconds() (ret int64) {
        ret = runtime_nanotime();
 }
+
+// Sleep puts the current goroutine to sleep for at least ns nanoseconds.
+func Sleep(ns int64) {
+       G *g;
+
+       g = runtime_g();
+       g->status = Gwaiting;
+       g->waitreason = "sleep";
+       runtime_tsleep(ns);
+}
+
+// startTimer adds t to the timer heap.
+func startTimer(t *Timer) {
+       addtimer(t);
+}
+
+// stopTimer removes t from the timer heap if it is there.
+// It returns true if t was removed, false if t wasn't even there.
+func stopTimer(t *Timer) (stopped bool) {
+       stopped = deltimer(t);
+}
+
+// C runtime.
+
+static void timerproc(void*);
+static void siftup(int32);
+static void siftdown(int32);
+
+// Ready the goroutine e.data.
+static void
+ready(int64 now, Eface e)
+{
+       USED(now);
+
+       runtime_ready(e.__object);
+}
+
+// Put the current goroutine to sleep for ns nanoseconds.
+// The caller must have set g->status and g->waitreason.
+void
+runtime_tsleep(int64 ns)
+{
+       Timer t;
+
+       if(ns <= 0)
+               return;
+
+       t.when = runtime_nanotime() + ns;
+       t.period = 0;
+       t.f = ready;
+       t.arg.__object = runtime_g();
+       addtimer(&t);
+       runtime_gosched();
+}
+
+// Add a timer to the heap and start or kick the timer proc
+// if the new timer is earlier than any of the others.
+static void
+addtimer(Timer *t)
+{
+       int32 n;
+       Timer **nt;
+
+       runtime_lock(&timers);
+       if(timers.len >= timers.cap) {
+               // Grow slice.
+               n = 16;
+               if(n <= timers.cap)
+                       n = timers.cap*3 / 2;
+               nt = runtime_malloc(n*sizeof nt[0]);
+               runtime_memmove(nt, timers.t, timers.len*sizeof nt[0]);
+               runtime_free(timers.t);
+               timers.t = nt;
+               timers.cap = n;
+       }
+       t->i = timers.len++;
+       timers.t[t->i] = t;
+       siftup(t->i);
+       if(t->i == 0) {
+               // siftup moved to top: new earliest deadline.
+               if(timers.sleeping) {
+                       timers.sleeping = false;
+                       runtime_notewakeup(&timers.waitnote);
+               }
+               if(timers.rescheduling) {
+                       timers.rescheduling = false;
+                       runtime_ready(timers.timerproc);
+               }
+       }
+       if(timers.timerproc == nil)
+               timers.timerproc = __go_go(timerproc, nil);
+       runtime_unlock(&timers);
+}
+
+// Delete timer t from the heap.
+// Do not need to update the timerproc:
+// if it wakes up early, no big deal.
+static bool
+deltimer(Timer *t)
+{
+       int32 i;
+
+       runtime_lock(&timers);
+
+       // t may not be registered anymore and may have
+       // a bogus i (typically 0, if generated by Go).
+       // Verify it before proceeding.
+       i = t->i;
+       if(i < 0 || i >= timers.len || timers.t[i] != t) {
+               runtime_unlock(&timers);
+               return false;
+       }
+
+       timers.len--;
+       if(i == timers.len) {
+               timers.t[i] = nil;
+       } else {
+               timers.t[i] = timers.t[timers.len];
+               timers.t[timers.len] = nil;
+               timers.t[i]->i = i;
+               siftup(i);
+               siftdown(i);
+       }
+       runtime_unlock(&timers);
+       return true;
+}
+
+// Timerproc runs the time-driven events.
+// It sleeps until the next event in the timers heap.
+// If addtimer inserts a new earlier event, addtimer
+// wakes timerproc early.
+static void
+timerproc(void* dummy __attribute__ ((unused)))
+{
+       G *g;
+       int64 delta, now;
+       Timer *t;
+       void (*f)(int64, Eface);
+       Eface arg;
+
+       g = runtime_g();
+       for(;;) {
+               runtime_lock(&timers);
+               now = runtime_nanotime();
+               for(;;) {
+                       if(timers.len == 0) {
+                               delta = -1;
+                               break;
+                       }
+                       t = timers.t[0];
+                       delta = t->when - now;
+                       if(delta > 0)
+                               break;
+                       if(t->period > 0) {
+                               // leave in heap but adjust next time to fire
+                               t->when += t->period * (1 + -delta/t->period);
+                               siftdown(0);
+                       } else {
+                               // remove from heap
+                               timers.t[0] = timers.t[--timers.len];
+                               timers.t[0]->i = 0;
+                               siftdown(0);
+                               t->i = -1;  // mark as removed
+                       }
+                       f = t->f;
+                       arg = t->arg;
+                       runtime_unlock(&timers);
+                       f(now, arg);
+                       runtime_lock(&timers);
+               }
+               if(delta < 0) {
+                       // No timers left - put goroutine to sleep.
+                       timers.rescheduling = true;
+                       g->status = Gwaiting;
+                       g->waitreason = "timer goroutine (idle)";
+                       runtime_unlock(&timers);
+                       runtime_gosched();
+                       continue;
+               }
+               // At least one timer pending.  Sleep until then.
+               timers.sleeping = true;
+               runtime_noteclear(&timers.waitnote);
+               runtime_unlock(&timers);
+               runtime_entersyscall();
+               runtime_notetsleep(&timers.waitnote, delta);
+               runtime_exitsyscall();
+       }
+}
+
+// heap maintenance algorithms.
+
+static void
+siftup(int32 i)
+{
+       int32 p;
+       Timer **t, *tmp;
+
+       t = timers.t;
+       while(i > 0) {
+               p = (i-1)/2;  // parent
+               if(t[i]->when >= t[p]->when)
+                       break;
+               tmp = t[i];
+               t[i] = t[p];
+               t[p] = tmp;
+               t[i]->i = i;
+               t[p]->i = p;
+               i = p;
+       }
+}
+
+static void
+siftdown(int32 i)
+{
+       int32 c, len;
+       Timer **t, *tmp;
+
+       t = timers.t;
+       len = timers.len;
+       for(;;) {
+               c = i*2 + 1;  // left child
+               if(c >= len) {
+                       break;
+               }
+               if(c+1 < len && t[c+1]->when < t[c]->when)
+                       c++;
+               if(t[c]->when >= t[i]->when)
+                       break;
+               tmp = t[i];
+               t[i] = t[c];
+               t[c] = tmp;
+               t[i]->i = i;
+               t[c]->i = c;
+               i = c;
+       }
+}
+
+void
+runtime_time_scan(void (*scan)(byte*, int64))
+{
+       scan((byte*)&timers, sizeof timers);
+}