libgo: Update to weekly.2011-12-22.
authorIan Lance Taylor <ian@gcc.gnu.org>
Fri, 13 Jan 2012 05:11:45 +0000 (05:11 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Fri, 13 Jan 2012 05:11:45 +0000 (05:11 +0000)
From-SVN: r183150

196 files changed:
gcc/testsuite/go.test/test/fixedbugs/bug229.go
libgo/MERGE
libgo/Makefile.am
libgo/Makefile.in
libgo/configure
libgo/configure.ac
libgo/go/archive/zip/reader_test.go
libgo/go/archive/zip/struct.go
libgo/go/archive/zip/zip_test.go
libgo/go/bytes/buffer_test.go
libgo/go/bytes/bytes_test.go
libgo/go/bytes/example_test.go [new file with mode: 0644]
libgo/go/crypto/aes/aes_test.go
libgo/go/crypto/crypto.go
libgo/go/crypto/openpgp/keys.go
libgo/go/crypto/rand/rand_unix.go
libgo/go/crypto/tls/common.go
libgo/go/crypto/tls/handshake_client.go
libgo/go/crypto/tls/key_agreement.go
libgo/go/crypto/tls/root_darwin.go
libgo/go/crypto/tls/root_stub.go
libgo/go/crypto/x509/cert_pool.go
libgo/go/crypto/x509/verify_test.go
libgo/go/crypto/x509/x509.go
libgo/go/debug/gosym/pclntab_test.go
libgo/go/encoding/binary/binary_test.go
libgo/go/encoding/binary/varint_test.go
libgo/go/encoding/gob/codec_test.go
libgo/go/encoding/gob/encode.go
libgo/go/encoding/gob/gobencdec_test.go
libgo/go/encoding/gob/timing_test.go
libgo/go/encoding/gob/type.go
libgo/go/encoding/json/bench_test.go
libgo/go/encoding/json/decode.go
libgo/go/encoding/json/decode_test.go
libgo/go/encoding/json/encode.go
libgo/go/encoding/xml/marshal_test.go
libgo/go/exp/inotify/inotify_linux_test.go
libgo/go/exp/sql/sql.go
libgo/go/exp/sql/sql_test.go
libgo/go/exp/ssh/client_auth.go
libgo/go/exp/ssh/client_auth_test.go
libgo/go/exp/ssh/client_func_test.go
libgo/go/exp/ssh/server.go
libgo/go/exp/ssh/session.go
libgo/go/exp/ssh/session_test.go
libgo/go/exp/ssh/tcpip.go
libgo/go/exp/terminal/terminal.go
libgo/go/exp/terminal/terminal_test.go
libgo/go/exp/terminal/util.go
libgo/go/exp/winfsnotify/winfsnotify.go
libgo/go/exp/winfsnotify/winfsnotify_test.go
libgo/go/exp/wingui/gui.go
libgo/go/exp/wingui/winapi.go
libgo/go/exp/wingui/zwinapi.go
libgo/go/fmt/fmt_test.go
libgo/go/fmt/format.go
libgo/go/fmt/print.go
libgo/go/go/ast/scope.go
libgo/go/go/build/build_test.go
libgo/go/go/build/dir.go
libgo/go/go/build/path.go
libgo/go/go/doc/doc.go
libgo/go/go/doc/exports.go [new file with mode: 0644]
libgo/go/go/doc/filter.go [new file with mode: 0644]
libgo/go/go/parser/parser.go
libgo/go/go/printer/nodes.go
libgo/go/go/printer/printer.go
libgo/go/go/printer/testdata/comments.golden
libgo/go/go/printer/testdata/comments.input
libgo/go/go/printer/testdata/declarations.golden
libgo/go/go/printer/testdata/declarations.input
libgo/go/go/printer/testdata/statements.golden
libgo/go/go/scanner/scanner.go
libgo/go/go/scanner/scanner_test.go
libgo/go/html/const.go
libgo/go/html/parse.go
libgo/go/html/parse_test.go
libgo/go/html/template/error.go
libgo/go/html/template/escape.go
libgo/go/html/template/escape_test.go
libgo/go/image/color/ycbcr.go [new file with mode: 0644]
libgo/go/image/color/ycbcr_test.go [new file with mode: 0644]
libgo/go/image/draw/bench_test.go
libgo/go/image/draw/draw.go
libgo/go/image/draw/draw_test.go
libgo/go/image/jpeg/reader.go
libgo/go/image/jpeg/writer.go
libgo/go/image/jpeg/writer_test.go
libgo/go/image/png/writer_test.go
libgo/go/image/tiff/reader_test.go
libgo/go/image/ycbcr.go [new file with mode: 0644]
libgo/go/image/ycbcr/ycbcr.go [deleted file]
libgo/go/image/ycbcr/ycbcr_test.go [deleted file]
libgo/go/io/ioutil/ioutil_test.go
libgo/go/log/syslog/syslog.go
libgo/go/math/all_test.go
libgo/go/math/big/int_test.go
libgo/go/math/big/nat.go
libgo/go/math/big/nat_test.go
libgo/go/math/sin.go
libgo/go/mime/type_unix.go
libgo/go/net/cgo_stub.go
libgo/go/net/dial.go
libgo/go/net/dial_test.go [new file with mode: 0644]
libgo/go/net/dnsclient_unix.go
libgo/go/net/dnsconfig.go
libgo/go/net/fd.go
libgo/go/net/fd_linux.go
libgo/go/net/fd_netbsd.go [new file with mode: 0644]
libgo/go/net/fd_openbsd.go
libgo/go/net/file.go
libgo/go/net/http/client.go
libgo/go/net/http/jar.go [new file with mode: 0644]
libgo/go/net/http/readrequest_test.go
libgo/go/net/http/request_test.go
libgo/go/net/http/serve_test.go
libgo/go/net/interface_bsd.go
libgo/go/net/interface_linux.go
libgo/go/net/interface_netbsd.go [new file with mode: 0644]
libgo/go/net/interface_test.go
libgo/go/net/ip.go
libgo/go/net/ipraw_test.go
libgo/go/net/iprawsock_posix.go
libgo/go/net/ipsock_posix.go
libgo/go/net/lookup_unix.go
libgo/go/net/net.go
libgo/go/net/newpollserver.go
libgo/go/net/port.go
libgo/go/net/rpc/server_test.go
libgo/go/net/sendfile_stub.go
libgo/go/net/sock.go
libgo/go/net/sock_bsd.go
libgo/go/net/tcpsock_posix.go
libgo/go/net/textproto/reader_test.go
libgo/go/net/udpsock_posix.go
libgo/go/net/unixsock_posix.go
libgo/go/old/regexp/all_test.go
libgo/go/old/template/template_test.go
libgo/go/os/dir_unix.go
libgo/go/os/error_posix.go
libgo/go/os/exec/exec.go
libgo/go/os/exec/exec_test.go
libgo/go/os/exec/lp_unix.go
libgo/go/os/exec_posix.go
libgo/go/os/exec_unix.go
libgo/go/os/file_posix.go
libgo/go/os/file_unix.go
libgo/go/os/os_test.go
libgo/go/os/os_unix_test.go
libgo/go/os/path_unix.go
libgo/go/os/signal/signal.go
libgo/go/os/signal/signal_test.go
libgo/go/os/sys_bsd.go
libgo/go/os/user/lookup_stubs.go
libgo/go/os/user/lookup_unix.go
libgo/go/path/filepath/path.go
libgo/go/path/filepath/path_test.go
libgo/go/path/filepath/path_unix.go
libgo/go/path/path.go
libgo/go/path/path_test.go
libgo/go/regexp/all_test.go
libgo/go/regexp/exec_test.go
libgo/go/sort/sort.go
libgo/go/strconv/atof.go
libgo/go/strconv/atof_test.go
libgo/go/strconv/decimal.go
libgo/go/strconv/extfloat.go [new file with mode: 0644]
libgo/go/strconv/ftoa.go
libgo/go/strings/strings_test.go
libgo/go/syscall/bpf_bsd.go
libgo/go/syscall/env_unix.go
libgo/go/syscall/exec_unix.go
libgo/go/syscall/route_bsd.go
libgo/go/syscall/route_netbsd.go [new file with mode: 0644]
libgo/go/syscall/sockcmsg_unix.go
libgo/go/syscall/socket_linux.go
libgo/go/syscall/syscall_unix.go
libgo/go/testing/benchmark.go
libgo/go/testing/example.go
libgo/go/testing/testing.go
libgo/go/testing/wrapper.go [new file with mode: 0644]
libgo/go/text/template/exec.go
libgo/go/text/template/exec_test.go
libgo/go/time/sys_unix.go
libgo/go/time/time.go
libgo/go/time/time_test.go
libgo/go/time/zoneinfo_unix.go
libgo/go/websocket/server.go
libgo/merge.sh
libgo/runtime/goc2c.c
libgo/runtime/lock_futex.c
libgo/runtime/lock_sema.c
libgo/runtime/mprof.goc
libgo/runtime/runtime.h
libgo/runtime/string.goc

index 6c9de9ba93eb85ba7cdbc6ee9f71c3962f9e24e2..a70a926da107cd1b148f05be7a8395bd65fd7f78 100644 (file)
@@ -12,9 +12,9 @@ func main() {
        var t testing.T
        
        // make sure error mentions that
-       // ch is unexported, not just "ch not found".
+       // name is unexported, not just "name not found".
 
-       t.ch = nil      // ERROR "unexported"
+       t.name = nil    // ERROR "unexported"
        
        println(testing.anyLowercaseName("asdf"))       // ERROR "unexported" "undefined: testing.anyLowercaseName"
 }
index bd71072101b68c0a93f16355e725393e811535d2..96fb7f66498e0cd28d80c714a48bbd242a2c2302 100644 (file)
@@ -1,4 +1,4 @@
-82fdc445f2ff
+4a8268927758
 
 The first line of this file holds the Mercurial revision number of the
 last merge done from the master library sources.
index 3c34c4b6bcb4cf076589f8f804d513f8943119b1..348a1cae8d2c4b570654372909ce34b08c32d9a1 100644 (file)
@@ -279,8 +279,7 @@ toolexeclibgoimage_DATA = \
        image/gif.gox \
        image/jpeg.gox \
        image/png.gox \
-       image/tiff.gox \
-       image/ycbcr.gox
+       image/tiff.gox
 
 toolexeclibgoindexdir = $(toolexeclibgodir)/index
 
@@ -586,7 +585,8 @@ go_image_files = \
        go/image/format.go \
        go/image/geom.go \
        go/image/image.go \
-       go/image/names.go
+       go/image/names.go \
+       go/image/ycbcr.go
 
 go_io_files = \
        go/io/multi.go \
@@ -654,10 +654,15 @@ if LIBGO_IS_LINUX
 go_net_fd_os_file = go/net/fd_linux.go
 go_net_newpollserver_file = go/net/newpollserver.go
 else # !LIBGO_IS_LINUX && !LIBGO_IS_RTEMS
+if LIBGO_IS_NETBSD
+go_net_fd_os_file = go/net/fd_netbsd.go
+go_net_newpollserver_file = go/net/newpollserver.go
+else # !LIBGO_IS_NETBSD && !LIBGO_IS_LINUX && !LIBGO_IS_RTEMS
 # By default use select with pipes.  Most systems should have
 # something better.
 go_net_fd_os_file = go/net/fd_select.go
 go_net_newpollserver_file = go/net/newpollserver.go
+endif # !LIBGO_IS_NETBSD
 endif # !LIBGO_IS_LINUX
 endif # !LIBGO_IS_RTEMS
 
@@ -688,8 +693,12 @@ endif
 if LIBGO_IS_LINUX
 go_net_interface_file = go/net/interface_linux.go
 else
+if LIBGO_IS_NETBSD
+go_net_interface_file = go/net/interface_netbsd.go
+else
 go_net_interface_file = go/net/interface_stub.go
 endif
+endif
 
 go_net_files = \
        go/net/cgo_unix.go \
@@ -845,6 +854,7 @@ go_strconv_files = \
        go/strconv/atof.go \
        go/strconv/atoi.go \
        go/strconv/decimal.go \
+       go/strconv/extfloat.go \
        go/strconv/ftoa.go \
        go/strconv/itoa.go \
        go/strconv/quote.go
@@ -880,7 +890,8 @@ go_syslog_c_files = \
 go_testing_files = \
        go/testing/benchmark.go \
        go/testing/example.go \
-       go/testing/testing.go
+       go/testing/testing.go \
+       go/testing/wrapper.go
 
 go_time_files = \
        go/time/format.go \
@@ -1197,7 +1208,9 @@ go_go_build_files = \
 go_go_doc_files = \
        go/go/doc/comment.go \
        go/go/doc/doc.go \
-       go/go/doc/example.go
+       go/go/doc/example.go \
+       go/go/doc/exports.go \
+       go/go/doc/filter.go
 go_go_parser_files = \
        go/go/parser/interface.go \
        go/go/parser/parser.go
@@ -1241,7 +1254,8 @@ go_image_bmp_files = \
        go/image/bmp/reader.go
 
 go_image_color_files = \
-       go/image/color/color.go
+       go/image/color/color.go \
+       go/image/color/ycbcr.go
 
 go_image_draw_files = \
        go/image/draw/draw.go
@@ -1266,9 +1280,6 @@ go_image_tiff_files = \
        go/image/tiff/consts.go \
        go/image/tiff/reader.go
 
-go_image_ycbcr_files = \
-       go/image/ycbcr/ycbcr.go
-
 go_index_suffixarray_files = \
        go/index/suffixarray/qsufsort.go \
        go/index/suffixarray/suffixarray.go
@@ -1318,6 +1329,7 @@ go_net_http_files = \
        go/net/http/filetransport.go \
        go/net/http/fs.go \
        go/net/http/header.go \
+       go/net/http/jar.go \
        go/net/http/lex.go \
        go/net/http/request.go \
        go/net/http/response.go \
@@ -1761,7 +1773,6 @@ libgo_go_objs = \
        image/jpeg.lo \
        image/png.lo \
        image/tiff.lo \
-       image/ycbcr.lo \
        index/suffixarray.lo \
        io/ioutil.lo \
        log/syslog.lo \
@@ -3066,16 +3077,6 @@ image/tiff/check: $(CHECK_DEPS)
        @$(CHECK)
 .PHONY: image/tiff/check
 
-@go_include@ image/ycbcr.lo.dep
-image/ycbcr.lo.dep: $(go_image_ycbcr_files)
-       $(BUILDDEPS)
-image/ycbcr.lo: $(go_image_ycbcr_files)
-       $(BUILDPACKAGE)
-image/ycbcr/check: $(CHECK_DEPS)
-       @$(MKDIR_P) image/ycbcr
-       @$(CHECK)
-.PHONY: image/ycbcr/check
-
 @go_include@ index/suffixarray.lo.dep
 index/suffixarray.lo.dep: $(go_index_suffixarray_files)
        $(BUILDDEPS)
@@ -3728,8 +3729,6 @@ image/png.gox: image/png.lo
        $(BUILDGOX)
 image/tiff.gox: image/tiff.lo
        $(BUILDGOX)
-image/ycbcr.gox: image/ycbcr.lo
-       $(BUILDGOX)
 
 index/suffixarray.gox: index/suffixarray.lo
        $(BUILDGOX)
@@ -3938,11 +3937,11 @@ TEST_PACKAGES = \
        hash/crc32/check \
        hash/crc64/check \
        hash/fnv/check \
+       image/color/check \
        image/draw/check \
        image/jpeg/check \
        image/png/check \
        image/tiff/check \
-       image/ycbcr/check \
        index/suffixarray/check \
        io/ioutil/check \
        log/syslog/check \
index ebc63f0f950613321725c69854382067480606d8..6bf18475628d9d50994ab43f89a6e7f26c0addd3 100644 (file)
@@ -167,20 +167,19 @@ am__DEPENDENCIES_2 = bufio/bufio.lo bytes/bytes.lo bytes/index.lo \
        hash/fnv.lo net/http/cgi.lo net/http/fcgi.lo \
        net/http/httptest.lo net/http/httputil.lo net/http/pprof.lo \
        image/bmp.lo image/color.lo image/draw.lo image/gif.lo \
-       image/jpeg.lo image/png.lo image/tiff.lo image/ycbcr.lo \
-       index/suffixarray.lo io/ioutil.lo log/syslog.lo \
-       log/syslog/syslog_c.lo math/big.lo math/cmplx.lo math/rand.lo \
-       mime/mime.lo mime/multipart.lo net/dict.lo net/http.lo \
-       net/mail.lo net/rpc.lo net/smtp.lo net/textproto.lo net/url.lo \
-       old/netchan.lo old/regexp.lo old/template.lo \
-       $(am__DEPENDENCIES_1) os/user.lo os/signal.lo path/filepath.lo \
-       regexp/syntax.lo net/rpc/jsonrpc.lo runtime/debug.lo \
-       runtime/pprof.lo sync/atomic.lo sync/atomic_c.lo \
-       syscall/syscall.lo syscall/errno.lo syscall/wait.lo \
-       text/scanner.lo text/tabwriter.lo text/template.lo \
-       text/template/parse.lo testing/testing.lo testing/iotest.lo \
-       testing/quick.lo testing/script.lo unicode/utf16.lo \
-       unicode/utf8.lo
+       image/jpeg.lo image/png.lo image/tiff.lo index/suffixarray.lo \
+       io/ioutil.lo log/syslog.lo log/syslog/syslog_c.lo math/big.lo \
+       math/cmplx.lo math/rand.lo mime/mime.lo mime/multipart.lo \
+       net/dict.lo net/http.lo net/mail.lo net/rpc.lo net/smtp.lo \
+       net/textproto.lo net/url.lo old/netchan.lo old/regexp.lo \
+       old/template.lo $(am__DEPENDENCIES_1) os/user.lo os/signal.lo \
+       path/filepath.lo regexp/syntax.lo net/rpc/jsonrpc.lo \
+       runtime/debug.lo runtime/pprof.lo sync/atomic.lo \
+       sync/atomic_c.lo syscall/syscall.lo syscall/errno.lo \
+       syscall/wait.lo text/scanner.lo text/tabwriter.lo \
+       text/template.lo text/template/parse.lo testing/testing.lo \
+       testing/iotest.lo testing/quick.lo testing/script.lo \
+       unicode/utf16.lo unicode/utf8.lo
 libgo_la_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \
        $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
        $(am__DEPENDENCIES_1)
@@ -732,8 +731,7 @@ toolexeclibgoimage_DATA = \
        image/gif.gox \
        image/jpeg.gox \
        image/png.gox \
-       image/tiff.gox \
-       image/ycbcr.gox
+       image/tiff.gox
 
 toolexeclibgoindexdir = $(toolexeclibgodir)/index
 toolexeclibgoindex_DATA = \
@@ -972,7 +970,8 @@ go_image_files = \
        go/image/format.go \
        go/image/geom.go \
        go/image/image.go \
-       go/image/names.go
+       go/image/names.go \
+       go/image/ycbcr.go
 
 go_io_files = \
        go/io/multi.go \
@@ -1034,10 +1033,12 @@ go_mime_files = \
 
 # By default use select with pipes.  Most systems should have
 # something better.
-@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_RTEMS_FALSE@go_net_fd_os_file = go/net/fd_select.go
+@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_RTEMS_FALSE@go_net_fd_os_file = go/net/fd_select.go
+@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_RTEMS_FALSE@go_net_fd_os_file = go/net/fd_netbsd.go
 @LIBGO_IS_LINUX_TRUE@@LIBGO_IS_RTEMS_FALSE@go_net_fd_os_file = go/net/fd_linux.go
 @LIBGO_IS_RTEMS_TRUE@go_net_fd_os_file = go/net/fd_select.go
-@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_RTEMS_FALSE@go_net_newpollserver_file = go/net/newpollserver.go
+@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_RTEMS_FALSE@go_net_newpollserver_file = go/net/newpollserver.go
+@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_RTEMS_FALSE@go_net_newpollserver_file = go/net/newpollserver.go
 @LIBGO_IS_LINUX_TRUE@@LIBGO_IS_RTEMS_FALSE@go_net_newpollserver_file = go/net/newpollserver.go
 @LIBGO_IS_RTEMS_TRUE@go_net_newpollserver_file = go/net/newpollserver_rtems.go
 @LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_cgo_file = go/net/cgo_bsd.go
@@ -1050,7 +1051,8 @@ go_mime_files = \
 @LIBGO_IS_LINUX_TRUE@go_net_sock_file = go/net/sock_linux.go
 @LIBGO_IS_LINUX_FALSE@go_net_sendfile_file = go/net/sendfile_stub.go
 @LIBGO_IS_LINUX_TRUE@go_net_sendfile_file = go/net/sendfile_linux.go
-@LIBGO_IS_LINUX_FALSE@go_net_interface_file = go/net/interface_stub.go
+@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@go_net_interface_file = go/net/interface_stub.go
+@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@go_net_interface_file = go/net/interface_netbsd.go
 @LIBGO_IS_LINUX_TRUE@go_net_interface_file = go/net/interface_linux.go
 go_net_files = \
        go/net/cgo_unix.go \
@@ -1165,6 +1167,7 @@ go_strconv_files = \
        go/strconv/atof.go \
        go/strconv/atoi.go \
        go/strconv/decimal.go \
+       go/strconv/extfloat.go \
        go/strconv/ftoa.go \
        go/strconv/itoa.go \
        go/strconv/quote.go
@@ -1194,7 +1197,8 @@ go_syslog_c_files = \
 go_testing_files = \
        go/testing/benchmark.go \
        go/testing/example.go \
-       go/testing/testing.go
+       go/testing/testing.go \
+       go/testing/wrapper.go
 
 go_time_files = \
        go/time/format.go \
@@ -1563,7 +1567,9 @@ go_go_build_files = \
 go_go_doc_files = \
        go/go/doc/comment.go \
        go/go/doc/doc.go \
-       go/go/doc/example.go
+       go/go/doc/example.go \
+       go/go/doc/exports.go \
+       go/go/doc/filter.go
 
 go_go_parser_files = \
        go/go/parser/interface.go \
@@ -1614,7 +1620,8 @@ go_image_bmp_files = \
        go/image/bmp/reader.go
 
 go_image_color_files = \
-       go/image/color/color.go
+       go/image/color/color.go \
+       go/image/color/ycbcr.go
 
 go_image_draw_files = \
        go/image/draw/draw.go
@@ -1639,9 +1646,6 @@ go_image_tiff_files = \
        go/image/tiff/consts.go \
        go/image/tiff/reader.go
 
-go_image_ycbcr_files = \
-       go/image/ycbcr/ycbcr.go
-
 go_index_suffixarray_files = \
        go/index/suffixarray/qsufsort.go \
        go/index/suffixarray/suffixarray.go
@@ -1694,6 +1698,7 @@ go_net_http_files = \
        go/net/http/filetransport.go \
        go/net/http/fs.go \
        go/net/http/header.go \
+       go/net/http/jar.go \
        go/net/http/lex.go \
        go/net/http/request.go \
        go/net/http/response.go \
@@ -2043,7 +2048,6 @@ libgo_go_objs = \
        image/jpeg.lo \
        image/png.lo \
        image/tiff.lo \
-       image/ycbcr.lo \
        index/suffixarray.lo \
        io/ioutil.lo \
        log/syslog.lo \
@@ -2299,11 +2303,11 @@ TEST_PACKAGES = \
        hash/crc32/check \
        hash/crc64/check \
        hash/fnv/check \
+       image/color/check \
        image/draw/check \
        image/jpeg/check \
        image/png/check \
        image/tiff/check \
-       image/ycbcr/check \
        index/suffixarray/check \
        io/ioutil/check \
        log/syslog/check \
@@ -5657,16 +5661,6 @@ image/tiff/check: $(CHECK_DEPS)
        @$(CHECK)
 .PHONY: image/tiff/check
 
-@go_include@ image/ycbcr.lo.dep
-image/ycbcr.lo.dep: $(go_image_ycbcr_files)
-       $(BUILDDEPS)
-image/ycbcr.lo: $(go_image_ycbcr_files)
-       $(BUILDPACKAGE)
-image/ycbcr/check: $(CHECK_DEPS)
-       @$(MKDIR_P) image/ycbcr
-       @$(CHECK)
-.PHONY: image/ycbcr/check
-
 @go_include@ index/suffixarray.lo.dep
 index/suffixarray.lo.dep: $(go_index_suffixarray_files)
        $(BUILDDEPS)
@@ -6314,8 +6308,6 @@ image/png.gox: image/png.lo
        $(BUILDGOX)
 image/tiff.gox: image/tiff.lo
        $(BUILDGOX)
-image/ycbcr.gox: image/ycbcr.lo
-       $(BUILDGOX)
 
 index/suffixarray.gox: index/suffixarray.lo
        $(BUILDGOX)
index c1ee7bac0826e77fe7ca8307a71dae5c52285175..7e8a38d37b4cc523b32d134d3b7ae5f550798c67 100755 (executable)
@@ -657,6 +657,8 @@ LIBGO_IS_SOLARIS_FALSE
 LIBGO_IS_SOLARIS_TRUE
 LIBGO_IS_RTEMS_FALSE
 LIBGO_IS_RTEMS_TRUE
+LIBGO_IS_NETBSD_FALSE
+LIBGO_IS_NETBSD_TRUE
 LIBGO_IS_LINUX_FALSE
 LIBGO_IS_LINUX_TRUE
 LIBGO_IS_IRIX_FALSE
@@ -11097,7 +11099,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11100 "configure"
+#line 11102 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11203,7 +11205,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11206 "configure"
+#line 11208 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -13473,6 +13475,7 @@ case ${host} in
   *-*-freebsd*)  is_freebsd=yes; GOOS=freebsd ;;
   *-*-irix6*)    is_irix=yes;    GOOS=irix ;;
   *-*-linux*)    is_linux=yes;   GOOS=linux ;;
+  *-*-netbsd*)  is_netbsd=yes;  GOOS=netbsd ;;
   *-*-rtems*)    is_rtems=yes;   GOOS=rtems ;;
   *-*-solaris2*) is_solaris=yes; GOOS=solaris ;;
 esac
@@ -13508,6 +13511,14 @@ else
   LIBGO_IS_LINUX_FALSE=
 fi
 
+ if test $is_netbsd = yes; then
+  LIBGO_IS_NETBSD_TRUE=
+  LIBGO_IS_NETBSD_FALSE='#'
+else
+  LIBGO_IS_NETBSD_TRUE='#'
+  LIBGO_IS_NETBSD_FALSE=
+fi
+
  if test $is_rtems = yes; then
   LIBGO_IS_RTEMS_TRUE=
   LIBGO_IS_RTEMS_FALSE='#'
@@ -14938,6 +14949,10 @@ if test -z "${LIBGO_IS_LINUX_TRUE}" && test -z "${LIBGO_IS_LINUX_FALSE}"; then
   as_fn_error "conditional \"LIBGO_IS_LINUX\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
+if test -z "${LIBGO_IS_NETBSD_TRUE}" && test -z "${LIBGO_IS_NETBSD_FALSE}"; then
+  as_fn_error "conditional \"LIBGO_IS_NETBSD\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
 if test -z "${LIBGO_IS_RTEMS_TRUE}" && test -z "${LIBGO_IS_RTEMS_FALSE}"; then
   as_fn_error "conditional \"LIBGO_IS_RTEMS\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
index a56106eaca94158d39ed5aae1a580bb1badb4e32..81326557afa350efa426c427d16ca2164a7d9a7b 100644 (file)
@@ -134,6 +134,7 @@ case ${host} in
   *-*-freebsd*)  is_freebsd=yes; GOOS=freebsd ;;
   *-*-irix6*)    is_irix=yes;    GOOS=irix ;;
   *-*-linux*)    is_linux=yes;   GOOS=linux ;;
+  *-*-netbsd*)  is_netbsd=yes;  GOOS=netbsd ;;
   *-*-rtems*)    is_rtems=yes;   GOOS=rtems ;;
   *-*-solaris2*) is_solaris=yes; GOOS=solaris ;;
 esac
@@ -141,6 +142,7 @@ AM_CONDITIONAL(LIBGO_IS_DARWIN, test $is_darwin = yes)
 AM_CONDITIONAL(LIBGO_IS_FREEBSD, test $is_freebsd = yes)
 AM_CONDITIONAL(LIBGO_IS_IRIX, test $is_irix = yes)
 AM_CONDITIONAL(LIBGO_IS_LINUX, test $is_linux = yes)
+AM_CONDITIONAL(LIBGO_IS_NETBSD, test $is_netbsd = yes)
 AM_CONDITIONAL(LIBGO_IS_RTEMS, test $is_rtems = yes)
 AM_CONDITIONAL(LIBGO_IS_SOLARIS, test $is_solaris = yes)
 AC_SUBST(GOOS)
index 9594fe8e508bc3b0e8b6382581853e2cf9f531bc..0e40268c2f8c5475733ebf2a1995f904f1f28c5e 100644 (file)
@@ -163,10 +163,10 @@ func readTestZip(t *testing.T, zt ZipTest) {
        done := make(chan bool)
        for i := 0; i < 5; i++ {
                for j, ft := range zt.File {
-                       go func() {
+                       go func(j int, ft ZipTestFile) {
                                readTestFile(t, ft, z.File[j])
                                done <- true
-                       }()
+                       }(j, ft)
                        n++
                }
        }
index c53a83c4e788cd01d5799dd92cd3e24ab4643908..34a87fae5b330596cf05d7221b939a7c8078fee6 100644 (file)
@@ -96,12 +96,28 @@ func msDosTimeToTime(dosDate, dosTime uint16) time.Time {
        )
 }
 
+// timeToMsDosTime converts a time.Time to an MS-DOS date and time.
+// The resolution is 2s.
+// See: http://msdn.microsoft.com/en-us/library/ms724274(v=VS.85).aspx
+func timeToMsDosTime(t time.Time) (fDate uint16, fTime uint16) {
+       t = t.In(time.UTC)
+       fDate = uint16(t.Day() + int(t.Month())<<5 + (t.Year()-1980)<<9)
+       fTime = uint16(t.Second()/2 + t.Minute()<<5 + t.Hour()<<11)
+       return
+}
+
 // ModTime returns the modification time.
 // The resolution is 2s.
 func (h *FileHeader) ModTime() time.Time {
        return msDosTimeToTime(h.ModifiedDate, h.ModifiedTime)
 }
 
+// SetModTime sets the ModifiedTime and ModifiedDate fields to the given time.
+// The resolution is 2s.
+func (h *FileHeader) SetModTime(t time.Time) {
+       h.ModifiedDate, h.ModifiedTime = timeToMsDosTime(t)
+}
+
 // traditional names for Unix constants
 const (
        s_IFMT  = 0xf000
index 2075715f3e01de96b42f30f99109729798236013..8aab2b68123f704c4e1a255f99a3daf8f49d59b2 100644 (file)
@@ -11,6 +11,7 @@ import (
        "fmt"
        "io"
        "testing"
+       "time"
 )
 
 type stringReaderAt string
@@ -55,3 +56,13 @@ func TestOver65kFiles(t *testing.T) {
                }
        }
 }
+
+func TestModTime(t *testing.T) {
+       var testTime = time.Date(2009, time.November, 10, 23, 45, 58, 0, time.UTC)
+       fh := new(FileHeader)
+       fh.SetModTime(testTime)
+       outTime := fh.ModTime()
+       if !outTime.Equal(testTime) {
+               t.Errorf("times don't match: got %s, want %s", outTime, testTime)
+       }
+}
index 523597003226100e1a1334c7bfcf17f5c60e5b48..adb93302a541ebcea1cc9ea6b7f9df1e055e11cb 100644 (file)
@@ -16,7 +16,6 @@ const N = 10000  // make this bigger for a larger (and slower) test
 var data string  // test data for write tests
 var bytes []byte // test data; same as data but as a slice.
 
-
 func init() {
        bytes = make([]byte, N)
        for i := 0; i < N; i++ {
index a2a08c20db0b83cb02729f73f867e8f372dab75e..2a1d41b910e3f222b091ccefe2eeac734f9edefa 100644 (file)
@@ -289,8 +289,7 @@ func bmIndexByte(b *testing.B, index func([]byte, byte) int, n int) {
        for i := 0; i < b.N; i++ {
                j := index(buf, 'x')
                if j != n-1 {
-                       println("bad index", j)
-                       panic("bad index")
+                       b.Fatal("bad index", j)
                }
        }
        buf[n-1] = '\x00'
@@ -317,7 +316,7 @@ func bmEqual(b *testing.B, equal func([]byte, []byte) bool, n int) {
        for i := 0; i < b.N; i++ {
                eq := equal(buf1, buf2)
                if !eq {
-                       panic("bad equal")
+                       b.Fatal("bad equal")
                }
        }
        buf1[n-1] = '\x00'
@@ -339,8 +338,7 @@ func bmIndex(b *testing.B, index func([]byte, []byte) int, n int) {
        for i := 0; i < b.N; i++ {
                j := index(buf, buf[n-7:])
                if j != n-7 {
-                       println("bad index", j)
-                       panic("bad index")
+                       b.Fatal("bad index", j)
                }
        }
        buf[n-1] = '\x00'
@@ -362,8 +360,7 @@ func bmIndexEasy(b *testing.B, index func([]byte, []byte) int, n int) {
        for i := 0; i < b.N; i++ {
                j := index(buf, buf[n-7:])
                if j != n-7 {
-                       println("bad index", j)
-                       panic("bad index")
+                       b.Fatal("bad index", j)
                }
        }
        buf[n-1] = '\x00'
@@ -385,8 +382,7 @@ func bmCount(b *testing.B, count func([]byte, []byte) int, n int) {
        for i := 0; i < b.N; i++ {
                j := count(buf, buf[n-7:])
                if j != 1 {
-                       println("bad count", j)
-                       panic("bad count")
+                       b.Fatal("bad count", j)
                }
        }
        buf[n-1] = '\x00'
@@ -408,8 +404,7 @@ func bmCountEasy(b *testing.B, count func([]byte, []byte) int, n int) {
        for i := 0; i < b.N; i++ {
                j := count(buf, buf[n-7:])
                if j != 1 {
-                       println("bad count", j)
-                       panic("bad count")
+                       b.Fatal("bad count", j)
                }
        }
        buf[n-1] = '\x00'
diff --git a/libgo/go/bytes/example_test.go b/libgo/go/bytes/example_test.go
new file mode 100644 (file)
index 0000000..02da1ac
--- /dev/null
@@ -0,0 +1,24 @@
+package bytes_test
+
+import (
+       . "bytes"
+       "encoding/base64"
+       "io"
+       "os"
+)
+
+// Hello world!
+func ExampleBuffer() {
+       var b Buffer // A Buffer needs no initialization.
+       b.Write([]byte("Hello "))
+       b.Write([]byte("world!"))
+       b.WriteTo(os.Stdout)
+}
+
+// Gophers rule!
+func ExampleBuffer_reader() {
+       // A Buffer can turn a string or a []byte into an io.Reader.
+       buf := NewBufferString("R29waGVycyBydWxlIQ==")
+       dec := base64.NewDecoder(base64.StdEncoding, buf)
+       io.Copy(os.Stdout, dec)
+}
index aa1d0df8e93996c5ed249f8a4830296ec5b34dba..e500c666d97ee42b62e4a6cc20d0343068ed649d 100644 (file)
@@ -356,7 +356,7 @@ func BenchmarkEncrypt(b *testing.B) {
        tt := encryptTests[0]
        c, err := NewCipher(tt.key)
        if err != nil {
-               panic("NewCipher")
+               b.Fatal("NewCipher:", err)
        }
        out := make([]byte, len(tt.in))
        b.StartTimer()
index 53672a4da3c9efc40931c5f721cc000eaa8a7186..c913494f61b92f1f0790ed4905e1757be8a9539f 100644 (file)
@@ -71,3 +71,6 @@ func RegisterHash(h Hash, f func() hash.Hash) {
        }
        hashes[h] = f
 }
+
+// PrivateKey represents a private key using an unspecified algorithm.
+type PrivateKey interface{}
index df39970c0b672d176253b22dad1cbfb1c93adb97..74e7d239e0882b2fc1ed1797c2b0befe173e5f42 100644 (file)
@@ -16,6 +16,7 @@ import (
 
 // PublicKeyType is the armor type for a PGP public key.
 var PublicKeyType = "PGP PUBLIC KEY BLOCK"
+
 // PrivateKeyType is the armor type for a PGP private key.
 var PrivateKeyType = "PGP PRIVATE KEY BLOCK"
 
index d9cddf6d2ad2830d61cad1d6ece74a78cd06eb2f..5d4fc8198ac8cf85182fdeb15f33d6c91a5b3b1d 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.
 
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
 
 // Unix cryptographically secure pseudorandom number
 // generator.
index f57d932a98f9a6602b51f61cf5ef032dcdb71481..a461ad951b011447f6bf4ed43f88a5dc1ad8548a 100644 (file)
@@ -5,8 +5,8 @@
 package tls
 
 import (
+       "crypto"
        "crypto/rand"
-       "crypto/rsa"
        "crypto/x509"
        "io"
        "strings"
@@ -255,7 +255,7 @@ func (c *Config) BuildNameToCertificate() {
 // A Certificate is a chain of one or more certificates, leaf first.
 type Certificate struct {
        Certificate [][]byte
-       PrivateKey  *rsa.PrivateKey
+       PrivateKey  crypto.PrivateKey // supported types: *rsa.PrivateKey
        // OCSPStaple contains an optional OCSP response which will be served
        // to clients that request it.
        OCSPStaple []byte
index e39e59cd5a1d05505bb92f63b67da4e2ab600466..73648002bd58bd74db619cb74a2fd89ac7cc322e 100644 (file)
@@ -234,7 +234,7 @@ func (c *Conn) clientHandshake() error {
                digest := make([]byte, 0, 36)
                digest = finishedHash.serverMD5.Sum(digest)
                digest = finishedHash.serverSHA1.Sum(digest)
-               signed, err := rsa.SignPKCS1v15(c.config.rand(), c.config.Certificates[0].PrivateKey, crypto.MD5SHA1, digest)
+               signed, err := rsa.SignPKCS1v15(c.config.rand(), c.config.Certificates[0].PrivateKey.(*rsa.PrivateKey), crypto.MD5SHA1, digest)
                if err != nil {
                        return c.sendAlert(alertInternalError)
                }
index b531717d8401c78d170a72aef5f3ca9cf2239e37..c3c16647853f043adcc5ed7864153c62213ac702 100644 (file)
@@ -44,7 +44,7 @@ func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKe
                ciphertext = ckx.ciphertext[2:]
        }
 
-       err = rsa.DecryptPKCS1v15SessionKey(config.rand(), config.Certificates[0].PrivateKey, ciphertext, preMasterSecret)
+       err = rsa.DecryptPKCS1v15SessionKey(config.rand(), config.Certificates[0].PrivateKey.(*rsa.PrivateKey), ciphertext, preMasterSecret)
        if err != nil {
                return nil, err
        }
@@ -147,7 +147,7 @@ Curve:
        copy(serverECDHParams[4:], ecdhePublic)
 
        md5sha1 := md5SHA1Hash(clientHello.random, hello.random, serverECDHParams)
-       sig, err := rsa.SignPKCS1v15(config.rand(), config.Certificates[0].PrivateKey, crypto.MD5SHA1, md5sha1)
+       sig, err := rsa.SignPKCS1v15(config.rand(), config.Certificates[0].PrivateKey.(*rsa.PrivateKey), crypto.MD5SHA1, md5sha1)
        if err != nil {
                return nil, errors.New("failed to sign ECDHE parameters: " + err.Error())
        }
index 15122416bd1ec162c14ebbcb7e00eb4c8b2ed2b7..db1b18b3c07dc7af2868de2dabec1a6bc0edb14a 100644 (file)
@@ -8,7 +8,7 @@ package tls
 // Note: We disable -Werror here because the code in this file uses a deprecated API to stay
 // compatible with both Mac OS X 10.6 and 10.7. Using a deprecated function on Darwin generates
 // a warning.
-#cgo CFLAGS: -Wno-error
+#cgo CFLAGS: -Wno-error -Wno-deprecated-declarations
 #cgo LDFLAGS: -framework CoreFoundation -framework Security
 #include <CoreFoundation/CoreFoundation.h>
 #include <Security/Security.h>
index 18dcb02043a6c8cbebb34ea35c14580c7a6758f8..d00493a5736d466291e3fc9684e5308b94db5571 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.
 
-// +build plan9
+// +build plan9 darwin/nocgo
 
 package tls
 
index adc7f9bc6d76e09bacbefd4703f9235b12f94756..5a0a87678e37336d238c23f222e89e1bbba05b45 100644 (file)
@@ -28,6 +28,9 @@ func NewCertPool() *CertPool {
 // given certificate. If no such certificate can be found or the signature
 // doesn't match, it returns nil.
 func (s *CertPool) findVerifiedParents(cert *Certificate) (parents []int) {
+       if s == nil {
+               return
+       }
        var candidates []int
 
        if len(cert.AuthorityKeyId) > 0 {
index df5443023ff9923d1633cb2df7e609309aaefe67..2016858307e275e8ec3f81d6d7be1d9dfd07545b 100644 (file)
@@ -19,6 +19,7 @@ type verifyTest struct {
        roots         []string
        currentTime   int64
        dnsName       string
+       nilRoots      bool
 
        errorCallback  func(*testing.T, int, error) bool
        expectedChains [][]string
@@ -45,6 +46,14 @@ var verifyTests = []verifyTest{
 
                errorCallback: expectHostnameError,
        },
+       {
+               leaf:          googleLeaf,
+               intermediates: []string{thawteIntermediate},
+               nilRoots:      true, // verifies that we don't crash
+               currentTime:   1302726541,
+               dnsName:       "www.google.com",
+               errorCallback: expectAuthorityUnknown,
+       },
        {
                leaf:          googleLeaf,
                intermediates: []string{thawteIntermediate},
@@ -136,6 +145,9 @@ func TestVerify(t *testing.T) {
                        DNSName:       test.dnsName,
                        CurrentTime:   time.Unix(test.currentTime, 0),
                }
+               if test.nilRoots {
+                       opts.Roots = nil
+               }
 
                for j, root := range test.roots {
                        ok := opts.Roots.AppendCertsFromPEM([]byte(root))
index 65ca31580035595f1a9d417f8276b97c86281dc6..28c7880e531922950c04d9a2d4bee9436103c0be 100644 (file)
@@ -981,6 +981,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.P
 // pemCRLPrefix is the magic string that indicates that we have a PEM encoded
 // CRL.
 var pemCRLPrefix = []byte("-----BEGIN X509 CRL")
+
 // pemType is the type of a PEM encoded CRL.
 var pemType = "X509 CRL"
 
index 562e7a0a37fff673d92e08d9fe2c893699364cdd..e5c29889b7f8d5510d658cb5a761ecff70a412e0 100644 (file)
@@ -13,7 +13,8 @@ import (
 
 func dotest() bool {
        // For now, only works on ELF platforms.
-       return syscall.OS == "linux" && os.Getenv("GOARCH") == "amd64"
+       // TODO: convert to work with new go tool
+       return false && syscall.OS == "linux" && os.Getenv("GOARCH") == "amd64"
 }
 
 func getTable(t *testing.T) *Table {
index fd4fdb015747ef1cab8b61f9a3bbdc2af8804355..3e7057ea22787066f2054d82f30ef0b92adbc7ff 100644 (file)
@@ -171,11 +171,42 @@ func (br *byteSliceReader) Read(p []byte) (int, error) {
        return n, nil
 }
 
-func BenchmarkRead(b *testing.B) {
+func BenchmarkReadSlice1000Int32s(b *testing.B) {
+       bsr := &byteSliceReader{}
+       slice := make([]int32, 1000)
+       buf := make([]byte, len(slice)*4)
+       b.SetBytes(int64(len(buf)))
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               bsr.remain = buf
+               Read(bsr, BigEndian, slice)
+       }
+}
+
+func BenchmarkReadStruct(b *testing.B) {
+       bsr := &byteSliceReader{}
+       var buf bytes.Buffer
+       Write(&buf, BigEndian, &s)
+       n := TotalSize(reflect.ValueOf(s))
+       b.SetBytes(int64(n))
+       t := s
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               bsr.remain = buf.Bytes()
+               Read(bsr, BigEndian, &t)
+       }
+       b.StopTimer()
+       if !reflect.DeepEqual(s, t) {
+               b.Fatal("no match")
+       }
+}
+
+func BenchmarkReadInts(b *testing.B) {
        var ls Struct
        bsr := &byteSliceReader{}
        var r io.Reader = bsr
-
+       b.SetBytes(2 * (1 + 2 + 4 + 8))
+       b.ResetTimer()
        for i := 0; i < b.N; i++ {
                bsr.remain = big
                Read(r, BigEndian, &ls.Int8)
@@ -196,25 +227,19 @@ func BenchmarkRead(b *testing.B) {
        for i := range want.Array {
                want.Array[i] = 0
        }
+       b.StopTimer()
        if !reflect.DeepEqual(ls, want) {
                panic("no match")
        }
 }
 
-func BenchmarkWrite(b *testing.B) {
+func BenchmarkWriteInts(b *testing.B) {
        buf := new(bytes.Buffer)
        var w io.Writer = buf
-
+       b.SetBytes(2 * (1 + 2 + 4 + 8))
+       b.ResetTimer()
        for i := 0; i < b.N; i++ {
                buf.Reset()
-               Write(w, BigEndian, &s.Int8)
-               Write(w, BigEndian, &s.Int16)
-               Write(w, BigEndian, &s.Int32)
-               Write(w, BigEndian, &s.Int64)
-               Write(w, BigEndian, &s.Uint8)
-               Write(w, BigEndian, &s.Uint16)
-               Write(w, BigEndian, &s.Uint32)
-               Write(w, BigEndian, &s.Uint64)
                Write(w, BigEndian, s.Int8)
                Write(w, BigEndian, s.Int16)
                Write(w, BigEndian, s.Int32)
@@ -224,11 +249,8 @@ func BenchmarkWrite(b *testing.B) {
                Write(w, BigEndian, s.Uint32)
                Write(w, BigEndian, s.Uint64)
        }
-
-       if !bytes.Equal(buf.Bytes()[:30], big[:30]) {
-               panic("first half doesn't match")
-       }
-       if !bytes.Equal(buf.Bytes()[30:], big[:30]) {
-               panic("second half doesn't match")
+       b.StopTimer()
+       if !bytes.Equal(buf.Bytes(), big[:30]) {
+               b.Fatalf("first half doesn't match: %x %x", buf.Bytes(), big[:30])
        }
 }
index b553d6d4eb0589af408e56a5935d4dab4844d8e5..dc550f22f44e79c9eaee865956dd4ef0884ee29d 100644 (file)
@@ -165,6 +165,7 @@ func TestNonCanonicalZero(t *testing.T) {
 
 func BenchmarkPutUvarint32(b *testing.B) {
        buf := make([]byte, MaxVarintLen32)
+       b.SetBytes(4)
        for i := 0; i < b.N; i++ {
                for j := uint(0); j < MaxVarintLen32; j++ {
                        PutUvarint(buf, 1<<(j*7))
@@ -174,6 +175,7 @@ func BenchmarkPutUvarint32(b *testing.B) {
 
 func BenchmarkPutUvarint64(b *testing.B) {
        buf := make([]byte, MaxVarintLen64)
+       b.SetBytes(8)
        for i := 0; i < b.N; i++ {
                for j := uint(0); j < MaxVarintLen64; j++ {
                        PutUvarint(buf, 1<<(j*7))
index dc0e0078e6810d1201e21722712fdaffd7d9ad76..73844b920c14bfa00fced5fd73ffc80df749ec73 100644 (file)
@@ -102,12 +102,15 @@ func TestIntCodec(t *testing.T) {
 
 // The result of encoding a true boolean with field number 7
 var boolResult = []byte{0x07, 0x01}
+
 // The result of encoding a number 17 with field number 7
 var signedResult = []byte{0x07, 2 * 17}
 var unsignedResult = []byte{0x07, 17}
 var floatResult = []byte{0x07, 0xFE, 0x31, 0x40}
+
 // The result of encoding a number 17+19i with field number 7
 var complexResult = []byte{0x07, 0xFE, 0x31, 0x40, 0xFE, 0x33, 0x40}
+
 // The result of encoding "hello" with field number 7
 var bytesResult = []byte{0x07, 0x05, 'h', 'e', 'l', 'l', 'o'}
 
index c7e48230c5306ebebd1cec9417ac24792ffe75c5..f05b17c309699e6684fbd75722680f6ba842118e 100644 (file)
@@ -469,7 +469,14 @@ func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv reflect.Value) {
 // isZero returns whether the value is the zero of its type.
 func isZero(val reflect.Value) bool {
        switch val.Kind() {
-       case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
+       case reflect.Array:
+               for i := 0; i < val.Len(); i++ {
+                       if !isZero(val.Index(i)) {
+                               return false
+                       }
+               }
+               return true
+       case reflect.Map, reflect.Slice, reflect.String:
                return val.Len() == 0
        case reflect.Bool:
                return !val.Bool()
@@ -483,6 +490,13 @@ func isZero(val reflect.Value) bool {
                return val.Float() == 0
        case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
                return val.Uint() == 0
+       case reflect.Struct:
+               for i := 0; i < val.NumField(); i++ {
+                       if !isZero(val.Field(i)) {
+                               return false
+                       }
+               }
+               return true
        }
        panic("unknown type in isZero " + val.Type().String())
 }
index eacfd842db383cd4997ed9ec623e662277f078db..b8dfeeb5156d0e066794ef749c3a6df588b8006d 100644 (file)
@@ -13,6 +13,7 @@ import (
        "io"
        "strings"
        "testing"
+       "time"
 )
 
 // Types that implement the GobEncoder/Decoder interfaces.
@@ -526,3 +527,50 @@ func TestGobEncoderExtraIndirect(t *testing.T) {
                t.Errorf("got = %q, want %q", got, gdb)
        }
 }
+
+// Another bug: this caused a crash with the new Go1 Time type.
+// We throw in a gob-encoding array, to test another case of isZero
+
+type isZeroBug struct {
+       T time.Time
+       S string
+       I int
+       A isZeroBugArray
+}
+
+type isZeroBugArray [2]uint8
+
+// Receiver is value, not pointer, to test isZero of array.
+func (a isZeroBugArray) GobEncode() (b []byte, e error) {
+       b = append(b, a[:]...)
+       return b, nil
+}
+
+func (a *isZeroBugArray) GobDecode(data []byte) error {
+       println("DECODE")
+       if len(data) != len(a) {
+               return io.EOF
+       }
+       a[0] = data[0]
+       a[1] = data[1]
+       return nil
+}
+
+func TestGobEncodeIsZero(t *testing.T) {
+       x := isZeroBug{time.Now(), "hello", -55, isZeroBugArray{1, 2}}
+       b := new(bytes.Buffer)
+       enc := NewEncoder(b)
+       err := enc.Encode(x)
+       if err != nil {
+               t.Fatal("encode:", err)
+       }
+       var y isZeroBug
+       dec := NewDecoder(b)
+       err = dec.Decode(&y)
+       if err != nil {
+               t.Fatal("decode:", err)
+       }
+       if x != y {
+               t.Fatalf("%v != %v", x, y)
+       }
+}
index 47437a607f1a3e9ec05e8da354e22d7de6ee8b5b..1017eb7f51d4100a8df8070360ef208b12b50c9a 100644 (file)
@@ -39,7 +39,7 @@ func benchmarkEndToEnd(r io.Reader, w io.Writer, b *testing.B) {
 func BenchmarkEndToEndPipe(b *testing.B) {
        r, w, err := os.Pipe()
        if err != nil {
-               panic("can't get pipe:" + err.Error())
+               b.Fatal("can't get pipe:", err)
        }
        benchmarkEndToEnd(r, w, b)
 }
index 1b20843fa2574004f7f9fa76da7736720fa702e4..71a28be7cab8a7a497145f9fdd692f95ab5dadc8 100644 (file)
@@ -130,6 +130,7 @@ func userType(rt reflect.Type) *userTypeInfo {
        }
        return ut
 }
+
 // A typeId represents a gob Type as an integer that can be passed on the wire.
 // Internally, typeIds are used as keys to a map to recover the underlying type info.
 type typeId int32
index f0c52011a1db594c18eefdee99f698ddca09920e..333c1c0ce9e3d13b63bfa9bd58543a6d5cd6bcad 100644 (file)
@@ -84,7 +84,7 @@ func BenchmarkCodeEncoder(b *testing.B) {
        enc := NewEncoder(ioutil.Discard)
        for i := 0; i < b.N; i++ {
                if err := enc.Encode(&codeStruct); err != nil {
-                       panic(err)
+                       b.Fatal("Encode:", err)
                }
        }
        b.SetBytes(int64(len(codeJSON)))
@@ -98,7 +98,7 @@ func BenchmarkCodeMarshal(b *testing.B) {
        }
        for i := 0; i < b.N; i++ {
                if _, err := Marshal(&codeStruct); err != nil {
-                       panic(err)
+                       b.Fatal("Marshal:", err)
                }
        }
        b.SetBytes(int64(len(codeJSON)))
@@ -120,7 +120,7 @@ func BenchmarkCodeDecoder(b *testing.B) {
                buf.WriteByte('\n')
                buf.WriteByte('\n')
                if err := dec.Decode(&r); err != nil {
-                       panic(err)
+                       b.Fatal("Decode:", err)
                }
        }
        b.SetBytes(int64(len(codeJSON)))
@@ -135,7 +135,7 @@ func BenchmarkCodeUnmarshal(b *testing.B) {
        for i := 0; i < b.N; i++ {
                var r codeResponse
                if err := Unmarshal(codeJSON, &r); err != nil {
-                       panic(err)
+                       b.Fatal("Unmmarshal:", err)
                }
        }
        b.SetBytes(int64(len(codeJSON)))
@@ -150,7 +150,7 @@ func BenchmarkCodeUnmarshalReuse(b *testing.B) {
        var r codeResponse
        for i := 0; i < b.N; i++ {
                if err := Unmarshal(codeJSON, &r); err != nil {
-                       panic(err)
+                       b.Fatal("Unmmarshal:", err)
                }
        }
        b.SetBytes(int64(len(codeJSON)))
index 0a700926296fe9f37c3099e35f0b19512f3aa96b..8287b330034ab01da4768e63c02e2672978daf09 100644 (file)
@@ -228,7 +228,9 @@ func (d *decodeState) value(v reflect.Value) {
                // Feed in an empty string - the shortest, simplest value -
                // so that it knows we got to the end of the value.
                if d.scan.redo {
-                       panic("redo")
+                       // rewind.
+                       d.scan.redo = false
+                       d.scan.step = stateBeginValue
                }
                d.scan.step(&d.scan, '"')
                d.scan.step(&d.scan, '"')
@@ -317,25 +319,22 @@ func (d *decodeState) array(v reflect.Value) {
        }
        v = pv
 
-       // Decoding into nil interface?  Switch to non-reflect code.
-       iv := v
-       ok := iv.Kind() == reflect.Interface
-       if ok {
-               iv.Set(reflect.ValueOf(d.arrayInterface()))
-               return
-       }
-
        // Check type of target.
-       av := v
-       if av.Kind() != reflect.Array && av.Kind() != reflect.Slice {
+       switch v.Kind() {
+       default:
                d.saveError(&UnmarshalTypeError{"array", v.Type()})
                d.off--
                d.next()
                return
+       case reflect.Interface:
+               // Decoding into nil interface?  Switch to non-reflect code.
+               v.Set(reflect.ValueOf(d.arrayInterface()))
+               return
+       case reflect.Array:
+       case reflect.Slice:
+               break
        }
 
-       sv := v
-
        i := 0
        for {
                // Look ahead for ] - can only happen on first iteration.
@@ -349,23 +348,25 @@ func (d *decodeState) array(v reflect.Value) {
                d.scan.undo(op)
 
                // Get element of array, growing if necessary.
-               if i >= av.Cap() && sv.IsValid() {
-                       newcap := sv.Cap() + sv.Cap()/2
-                       if newcap < 4 {
-                               newcap = 4
+               if v.Kind() == reflect.Slice {
+                       // Grow slice if necessary
+                       if i >= v.Cap() {
+                               newcap := v.Cap() + v.Cap()/2
+                               if newcap < 4 {
+                                       newcap = 4
+                               }
+                               newv := reflect.MakeSlice(v.Type(), v.Len(), newcap)
+                               reflect.Copy(newv, v)
+                               v.Set(newv)
+                       }
+                       if i >= v.Len() {
+                               v.SetLen(i + 1)
                        }
-                       newv := reflect.MakeSlice(sv.Type(), sv.Len(), newcap)
-                       reflect.Copy(newv, sv)
-                       sv.Set(newv)
-               }
-               if i >= av.Len() && sv.IsValid() {
-                       // Must be slice; gave up on array during i >= av.Cap().
-                       sv.SetLen(i + 1)
                }
 
-               // Decode into element.
-               if i < av.Len() {
-                       d.value(av.Index(i))
+               if i < v.Len() {
+                       // Decode into element.
+                       d.value(v.Index(i))
                } else {
                        // Ran out of fixed array: skip.
                        d.value(reflect.Value{})
@@ -382,19 +383,19 @@ func (d *decodeState) array(v reflect.Value) {
                }
        }
 
-       if i < av.Len() {
-               if !sv.IsValid() {
+       if i < v.Len() {
+               if v.Kind() == reflect.Array {
                        // Array.  Zero the rest.
-                       z := reflect.Zero(av.Type().Elem())
-                       for ; i < av.Len(); i++ {
-                               av.Index(i).Set(z)
+                       z := reflect.Zero(v.Type().Elem())
+                       for ; i < v.Len(); i++ {
+                               v.Index(i).Set(z)
                        }
                } else {
-                       sv.SetLen(i)
+                       v.SetLen(i)
                }
        }
-       if i == 0 && av.Kind() == reflect.Slice && sv.IsNil() {
-               sv.Set(reflect.MakeSlice(sv.Type(), 0, 0))
+       if i == 0 && v.Kind() == reflect.Slice {
+               v.Set(reflect.MakeSlice(v.Type(), 0, 0))
        }
 }
 
index bf3953eb051f908ee9299f318afec1654408cf55..05c8a064a422c8bba383aa1683ebaa72a0ea4793 100644 (file)
@@ -6,6 +6,7 @@ package json
 
 import (
        "bytes"
+       "fmt"
        "reflect"
        "strings"
        "testing"
@@ -73,6 +74,12 @@ var unmarshalTests = []unmarshalTest{
 
        // syntax errors
        {`{"X": "foo", "Y"}`, nil, nil, &SyntaxError{"invalid character '}' after object key", 17}},
+       {`[1, 2, 3+]`, nil, nil, &SyntaxError{"invalid character '+' after array element", 9}},
+
+       // array tests
+       {`[1, 2, 3]`, new([3]int), [3]int{1, 2, 3}, nil},
+       {`[1, 2, 3]`, new([1]int), [1]int{1}, nil},
+       {`[1, 2, 3]`, new([5]int), [5]int{1, 2, 3, 0, 0}, nil},
 
        // composite tests
        {allValueIndent, new(All), allValue, nil},
@@ -242,6 +249,38 @@ func TestHTMLEscape(t *testing.T) {
        }
 }
 
+// WrongString is a struct that's misusing the ,string modifier.
+type WrongString struct {
+       Message string `json:"result,string"`
+}
+
+type wrongStringTest struct {
+       in, err string
+}
+
+// TODO(bradfitz): as part of Issue 2331, fix these tests' expected
+// error values to be helpful, rather than the confusing messages they
+// are now.
+var wrongStringTests = []wrongStringTest{
+       {`{"result":"x"}`, "JSON decoder out of sync - data changing underfoot?"},
+       {`{"result":"foo"}`, "json: cannot unmarshal bool into Go value of type string"},
+       {`{"result":"123"}`, "json: cannot unmarshal number into Go value of type string"},
+}
+
+// If people misuse the ,string modifier, the error message should be
+// helpful, telling the user that they're doing it wrong.
+func TestErrorMessageFromMisusedString(t *testing.T) {
+       for n, tt := range wrongStringTests {
+               r := strings.NewReader(tt.in)
+               var s WrongString
+               err := NewDecoder(r).Decode(&s)
+               got := fmt.Sprintf("%v", err)
+               if got != tt.err {
+                       t.Errorf("%d. got err = %q, want %q", n, got, tt.err)
+               }
+       }
+}
+
 func noSpace(c rune) rune {
        if isSpace(c) {
                return -1
index ff8e80c091ed0876e24a99b179417ac71eea558c..3d2f4fc316ea8e837995399d637851d3832ac7c3 100644 (file)
@@ -197,6 +197,7 @@ var hex = "0123456789abcdef"
 // An encodeState encodes JSON into a bytes.Buffer.
 type encodeState struct {
        bytes.Buffer // accumulated output
+       scratch      [64]byte
 }
 
 func (e *encodeState) marshal(v interface{}) (err error) {
@@ -275,14 +276,26 @@ func (e *encodeState) reflectValueQuoted(v reflect.Value, quoted bool) {
                }
 
        case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-               writeString(e, strconv.FormatInt(v.Int(), 10))
-
+               b := strconv.AppendInt(e.scratch[:0], v.Int(), 10)
+               if quoted {
+                       writeString(e, string(b))
+               } else {
+                       e.Write(b)
+               }
        case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
-               writeString(e, strconv.FormatUint(v.Uint(), 10))
-
+               b := strconv.AppendUint(e.scratch[:0], v.Uint(), 10)
+               if quoted {
+                       writeString(e, string(b))
+               } else {
+                       e.Write(b)
+               }
        case reflect.Float32, reflect.Float64:
-               writeString(e, strconv.FormatFloat(v.Float(), 'g', -1, v.Type().Bits()))
-
+               b := strconv.AppendFloat(e.scratch[:0], v.Float(), 'g', -1, v.Type().Bits())
+               if quoted {
+                       writeString(e, string(b))
+               } else {
+                       e.Write(b)
+               }
        case reflect.String:
                if quoted {
                        sb, err := Marshal(v.String())
index 804076580155a77dd22ea07bcf028905a2be4ac4..6a241694baf85651ad1082c7f354975fa599e4d0 100644 (file)
@@ -394,7 +394,7 @@ func TestUnmarshal(t *testing.T) {
                if err != nil {
                        t.Errorf("#%d: unexpected error: %#v", i, err)
                } else if got, want := dest, test.Value; !reflect.DeepEqual(got, want) {
-                       t.Errorf("#%d: unmarshal(%#s) = %#v, want %#v", i, test.ExpectXML, got, want)
+                       t.Errorf("#%d: unmarshal(%q) = %#v, want %#v", i, test.ExpectXML, got, want)
                }
        }
 }
index 92384b693761ac025f97f33f720e838be4690da2..d035ec1410ff16afd9daa9a349e29de06ff5c18b 100644 (file)
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build linux
+
 package inotify
 
 import (
@@ -17,6 +19,9 @@ func TestInotifyEvents(t *testing.T) {
                t.Fatalf("NewWatcher() failed: %s", err)
        }
 
+       t.Logf("NEEDS TO BE CONVERTED TO NEW GO TOOL") // TODO
+       return
+
        // Add a watch for "_test"
        err = watcher.Watch("_test")
        if err != nil {
index 948b911f2e0a0ef554eff75a823afcc8cabececf..937982cdbe6f9b3661ea963047f0efe9d92fd828 100644 (file)
@@ -22,10 +22,10 @@ var drivers = make(map[string]driver.Driver)
 // it panics.
 func Register(name string, driver driver.Driver) {
        if driver == nil {
-               panic("db: Register driver is nil")
+               panic("sql: Register driver is nil")
        }
        if _, dup := drivers[name]; dup {
-               panic("db: Register called twice for driver " + name)
+               panic("sql: Register called twice for driver " + name)
        }
        drivers[name] = driver
 }
@@ -80,7 +80,7 @@ type ScannerInto interface {
 // ErrNoRows is returned by Scan when QueryRow doesn't return a
 // row. In such a case, QueryRow returns a placeholder *Row value that
 // defers this error until a Scan.
-var ErrNoRows = errors.New("db: no rows in result set")
+var ErrNoRows = errors.New("sql: no rows in result set")
 
 // DB is a database handle. It's safe for concurrent use by multiple
 // goroutines.
@@ -102,7 +102,7 @@ type DB struct {
 func Open(driverName, dataSourceName string) (*DB, error) {
        driver, ok := drivers[driverName]
        if !ok {
-               return nil, fmt.Errorf("db: unknown driver %q (forgotten import?)", driverName)
+               return nil, fmt.Errorf("sql: unknown driver %q (forgotten import?)", driverName)
        }
        return &DB{driver: driver, dsn: dataSourceName}, nil
 }
@@ -514,7 +514,7 @@ func (s *Stmt) Exec(args ...interface{}) (Result, error) {
        // placeholders, so we won't sanity check input here and instead let the
        // driver deal with errors.
        if want := si.NumInput(); want != -1 && len(args) != want {
-               return nil, fmt.Errorf("db: expected %d arguments, got %d", want, len(args))
+               return nil, fmt.Errorf("sql: expected %d arguments, got %d", want, len(args))
        }
 
        // Convert args to subset types.
@@ -522,10 +522,10 @@ func (s *Stmt) Exec(args ...interface{}) (Result, error) {
                for n, arg := range args {
                        args[n], err = cc.ColumnConverter(n).ConvertValue(arg)
                        if err != nil {
-                               return nil, fmt.Errorf("db: converting Exec argument #%d's type: %v", n, err)
+                               return nil, fmt.Errorf("sql: converting Exec argument #%d's type: %v", n, err)
                        }
                        if !driver.IsParameterSubsetType(args[n]) {
-                               return nil, fmt.Errorf("db: driver ColumnConverter error converted %T to unsupported type %T",
+                               return nil, fmt.Errorf("sql: driver ColumnConverter error converted %T to unsupported type %T",
                                        arg, args[n])
                        }
                }
@@ -533,7 +533,7 @@ func (s *Stmt) Exec(args ...interface{}) (Result, error) {
                for n, arg := range args {
                        args[n], err = driver.DefaultParameterConverter.ConvertValue(arg)
                        if err != nil {
-                               return nil, fmt.Errorf("db: converting Exec argument #%d's type: %v", n, err)
+                               return nil, fmt.Errorf("sql: converting Exec argument #%d's type: %v", n, err)
                        }
                }
        }
@@ -555,7 +555,7 @@ func (s *Stmt) connStmt() (ci driver.Conn, releaseConn func(), si driver.Stmt, e
        s.mu.Lock()
        if s.closed {
                s.mu.Unlock()
-               err = errors.New("db: statement is closed")
+               err = errors.New("sql: statement is closed")
                return
        }
 
@@ -617,7 +617,7 @@ func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
        // placeholders, so we won't sanity check input here and instead let the
        // driver deal with errors.
        if want := si.NumInput(); want != -1 && len(args) != want {
-               return nil, fmt.Errorf("db: statement expects %d inputs; got %d", si.NumInput(), len(args))
+               return nil, fmt.Errorf("sql: statement expects %d inputs; got %d", si.NumInput(), len(args))
        }
        sargs, err := subsetTypeArgs(args)
        if err != nil {
@@ -737,27 +737,40 @@ func (rs *Rows) Err() error {
        return rs.lasterr
 }
 
+// Columns returns the column names.
+// Columns returns an error if the rows are closed, or if the rows
+// are from QueryRow and there was a deferred error.
+func (rs *Rows) Columns() ([]string, error) {
+       if rs.closed {
+               return nil, errors.New("sql: Rows are closed")
+       }
+       if rs.rowsi == nil {
+               return nil, errors.New("sql: no Rows available")
+       }
+       return rs.rowsi.Columns(), nil
+}
+
 // Scan copies the columns in the current row into the values pointed
 // at by dest. If dest contains pointers to []byte, the slices should
 // not be modified and should only be considered valid until the next
 // call to Next or Scan.
 func (rs *Rows) Scan(dest ...interface{}) error {
        if rs.closed {
-               return errors.New("db: Rows closed")
+               return errors.New("sql: Rows closed")
        }
        if rs.lasterr != nil {
                return rs.lasterr
        }
        if rs.lastcols == nil {
-               return errors.New("db: Scan called without calling Next")
+               return errors.New("sql: Scan called without calling Next")
        }
        if len(dest) != len(rs.lastcols) {
-               return fmt.Errorf("db: expected %d destination arguments in Scan, not %d", len(rs.lastcols), len(dest))
+               return fmt.Errorf("sql: expected %d destination arguments in Scan, not %d", len(rs.lastcols), len(dest))
        }
        for i, sv := range rs.lastcols {
                err := convertAssign(dest[i], sv)
                if err != nil {
-                       return fmt.Errorf("db: Scan error on column index %d: %v", i, err)
+                       return fmt.Errorf("sql: Scan error on column index %d: %v", i, err)
                }
        }
        return nil
index f8ccf764e73ada4f56fe86acab7866e693788974..5307a235ddf13fc0eb84b09eb7da9e3358ed0f3a 100644 (file)
@@ -75,6 +75,23 @@ func TestQuery(t *testing.T) {
        }
 }
 
+func TestRowsColumns(t *testing.T) {
+       db := newTestDB(t, "people")
+       defer closeDB(t, db)
+       rows, err := db.Query("SELECT|people|age,name|")
+       if err != nil {
+               t.Fatalf("Query: %v", err)
+       }
+       cols, err := rows.Columns()
+       if err != nil {
+               t.Fatalf("Columns: %v", err)
+       }
+       want := []string{"age", "name"}
+       if !reflect.DeepEqual(cols, want) {
+               t.Errorf("got %#v; want %#v", cols, want)
+       }
+}
+
 func TestQueryRow(t *testing.T) {
        db := newTestDB(t, "people")
        defer closeDB(t, db)
@@ -187,12 +204,12 @@ func TestExec(t *testing.T) {
                {[]interface{}{7, 9}, ""},
 
                // Invalid conversions:
-               {[]interface{}{"Brad", int64(0xFFFFFFFF)}, "db: converting Exec argument #1's type: sql/driver: value 4294967295 overflows int32"},
-               {[]interface{}{"Brad", "strconv fail"}, "db: converting Exec argument #1's type: sql/driver: value \"strconv fail\" can't be converted to int32"},
+               {[]interface{}{"Brad", int64(0xFFFFFFFF)}, "sql: converting Exec argument #1's type: sql/driver: value 4294967295 overflows int32"},
+               {[]interface{}{"Brad", "strconv fail"}, "sql: converting Exec argument #1's type: sql/driver: value \"strconv fail\" can't be converted to int32"},
 
                // Wrong number of args:
-               {[]interface{}{}, "db: expected 2 arguments, got 0"},
-               {[]interface{}{1, 2, 3}, "db: expected 2 arguments, got 3"},
+               {[]interface{}{}, "sql: expected 2 arguments, got 0"},
+               {[]interface{}{1, 2, 3}, "sql: expected 2 arguments, got 3"},
        }
        for n, et := range execTests {
                _, err := stmt.Exec(et.args...)
index 1a382357b46e7100e3657d8d26d03dde93269134..3a7e9fb98017681e6da7e4dfdd3dd333d35f4067 100644 (file)
@@ -283,8 +283,8 @@ func (p *publickeyAuth) method() string {
        return "publickey"
 }
 
-// ClientAuthPublickey returns a ClientAuth using public key authentication.
-func ClientAuthPublickey(impl ClientKeyring) ClientAuth {
+// ClientAuthKeyring returns a ClientAuth using public key authentication.
+func ClientAuthKeyring(impl ClientKeyring) ClientAuth {
        return &publickeyAuth{impl}
 }
 
index 2b89e9728c783397ba049775362e1e58e6b93eca..c41a93b5c7dbf91c0de8961b1b2d4907b9036ee7 100644 (file)
@@ -122,7 +122,7 @@ var (
                PasswordCallback: func(user, pass string) bool {
                        return user == "testuser" && pass == string(clientPassword)
                },
-               PubKeyCallback: func(user, algo string, pubkey []byte) bool {
+               PublicKeyCallback: func(user, algo string, pubkey []byte) bool {
                        key := clientKeychain.keys[0].(*rsa.PrivateKey).PublicKey
                        expected := []byte(serializePublickey(key))
                        algoname := algoName(key)
@@ -179,7 +179,7 @@ func TestClientAuthPublickey(t *testing.T) {
        config := &ClientConfig{
                User: "testuser",
                Auth: []ClientAuth{
-                       ClientAuthPublickey(clientKeychain),
+                       ClientAuthKeyring(clientKeychain),
                },
        }
        c, err := Dial("tcp", newMockAuthServer(t), config)
@@ -210,7 +210,7 @@ func TestClientAuthWrongPassword(t *testing.T) {
                User: "testuser",
                Auth: []ClientAuth{
                        ClientAuthPassword(wrongPw),
-                       ClientAuthPublickey(clientKeychain),
+                       ClientAuthKeyring(clientKeychain),
                },
        }
 
@@ -228,7 +228,7 @@ func TestClientAuthInvalidPublickey(t *testing.T) {
        config := &ClientConfig{
                User: "testuser",
                Auth: []ClientAuth{
-                       ClientAuthPublickey(kc),
+                       ClientAuthKeyring(kc),
                },
        }
 
@@ -246,7 +246,7 @@ func TestClientAuthRSAandDSA(t *testing.T) {
        config := &ClientConfig{
                User: "testuser",
                Auth: []ClientAuth{
-                       ClientAuthPublickey(kc),
+                       ClientAuthKeyring(kc),
                },
        }
        c, err := Dial("tcp", newMockAuthServer(t), config)
index 24e3a6334e50ef3e735594cc54b85c1b20d8ce24..b4bdba95396bcc64c83e33482bd2ef337dff3bac 100644 (file)
@@ -50,7 +50,7 @@ func TestFuncPublickeyAuth(t *testing.T) {
        config := &ClientConfig{
                User: *sshuser,
                Auth: []ClientAuth{
-                       ClientAuthPublickey(kc),
+                       ClientAuthKeyring(kc),
                },
        }
        conn, err := Dial("tcp", "localhost:22", config)
index 1eee9a4a9776c05ff2605cd25f7c0fb1383b38b0..31011c6617677658f1b2a4f1138534b49134e8ab 100644 (file)
@@ -36,10 +36,10 @@ type ServerConfig struct {
        // several goroutines.
        PasswordCallback func(user, password string) bool
 
-       // PubKeyCallback, if non-nil, is called when a client attempts public
+       // PublicKeyCallback, if non-nil, is called when a client attempts public
        // key authentication. It must return true iff the given public key is
        // valid for the given user.
-       PubKeyCallback func(user, algo string, pubkey []byte) bool
+       PublicKeyCallback func(user, algo string, pubkey []byte) bool
 
        // Cryptographic-related configuration.
        Crypto CryptoConfig
@@ -359,7 +359,7 @@ func isAcceptableAlgo(algo string) bool {
 
 // testPubKey returns true if the given public key is acceptable for the user.
 func (s *ServerConn) testPubKey(user, algo string, pubKey []byte) bool {
-       if s.config.PubKeyCallback == nil || !isAcceptableAlgo(algo) {
+       if s.config.PublicKeyCallback == nil || !isAcceptableAlgo(algo) {
                return false
        }
 
@@ -369,7 +369,7 @@ func (s *ServerConn) testPubKey(user, algo string, pubKey []byte) bool {
                }
        }
 
-       result := s.config.PubKeyCallback(user, algo, pubKey)
+       result := s.config.PublicKeyCallback(user, algo, pubKey)
        if len(s.cachedPubKeys) < maxCachedPubKeys {
                c := cachedPubKey{
                        user:   user,
@@ -425,7 +425,7 @@ userAuthLoop:
                                break userAuthLoop
                        }
                case "publickey":
-                       if s.config.PubKeyCallback == nil {
+                       if s.config.PublicKeyCallback == nil {
                                break
                        }
                        payload := userAuthReq.Payload
@@ -499,7 +499,7 @@ userAuthLoop:
                if s.config.PasswordCallback != nil {
                        failureMsg.Methods = append(failureMsg.Methods, "password")
                }
-               if s.config.PubKeyCallback != nil {
+               if s.config.PublicKeyCallback != nil {
                        failureMsg.Methods = append(failureMsg.Methods, "publickey")
                }
 
index bf9a88e97efc39ad7fd46fbd39754b3ac470fae1..807dd8740d780eb42bc1eb0190564d089edb4662 100644 (file)
@@ -68,10 +68,12 @@ type Session struct {
 
        *clientChan // the channel backing this session
 
-       started        bool // true once Start, Run or Shell is invoked.
-       closeAfterWait []io.Closer
-       copyFuncs      []func() error
-       errch          chan error // one send per copyFunc
+       started   bool // true once Start, Run or Shell is invoked.
+       copyFuncs []func() error
+       errch     chan error // one send per copyFunc
+
+       // true if pipe method is active
+       stdinpipe, stdoutpipe, stderrpipe bool
 }
 
 // RFC 4254 Section 6.4.
@@ -237,11 +239,9 @@ func (s *Session) waitForResponse() error {
 func (s *Session) start() error {
        s.started = true
 
-       type F func(*Session) error
+       type F func(*Session)
        for _, setupFd := range []F{(*Session).stdin, (*Session).stdout, (*Session).stderr} {
-               if err := setupFd(s); err != nil {
-                       return err
-               }
+               setupFd(s)
        }
 
        s.errch = make(chan error, len(s.copyFuncs))
@@ -274,9 +274,6 @@ func (s *Session) Wait() error {
                        copyError = err
                }
        }
-       for _, fd := range s.closeAfterWait {
-               fd.Close()
-       }
        if waitErr != nil {
                return waitErr
        }
@@ -341,7 +338,10 @@ func (s *Session) wait() error {
        return &ExitError{wm}
 }
 
-func (s *Session) stdin() error {
+func (s *Session) stdin() {
+       if s.stdinpipe {
+               return
+       }
        if s.Stdin == nil {
                s.Stdin = new(bytes.Buffer)
        }
@@ -352,10 +352,12 @@ func (s *Session) stdin() error {
                }
                return err
        })
-       return nil
 }
 
-func (s *Session) stdout() error {
+func (s *Session) stdout() {
+       if s.stdoutpipe {
+               return
+       }
        if s.Stdout == nil {
                s.Stdout = ioutil.Discard
        }
@@ -363,10 +365,12 @@ func (s *Session) stdout() error {
                _, err := io.Copy(s.Stdout, s.clientChan.stdout)
                return err
        })
-       return nil
 }
 
-func (s *Session) stderr() error {
+func (s *Session) stderr() {
+       if s.stderrpipe {
+               return
+       }
        if s.Stderr == nil {
                s.Stderr = ioutil.Discard
        }
@@ -374,7 +378,6 @@ func (s *Session) stderr() error {
                _, err := io.Copy(s.Stderr, s.clientChan.stderr)
                return err
        })
-       return nil
 }
 
 // StdinPipe returns a pipe that will be connected to the
@@ -386,10 +389,8 @@ func (s *Session) StdinPipe() (io.WriteCloser, error) {
        if s.started {
                return nil, errors.New("ssh: StdinPipe after process started")
        }
-       pr, pw := io.Pipe()
-       s.Stdin = pr
-       s.closeAfterWait = append(s.closeAfterWait, pr)
-       return pw, nil
+       s.stdinpipe = true
+       return s.clientChan.stdin, nil
 }
 
 // StdoutPipe returns a pipe that will be connected to the
@@ -398,17 +399,15 @@ func (s *Session) StdinPipe() (io.WriteCloser, error) {
 // stdout and stderr streams. If the StdoutPipe reader is
 // not serviced fast enought it may eventually cause the
 // remote command to block.
-func (s *Session) StdoutPipe() (io.ReadCloser, error) {
+func (s *Session) StdoutPipe() (io.Reader, error) {
        if s.Stdout != nil {
                return nil, errors.New("ssh: Stdout already set")
        }
        if s.started {
                return nil, errors.New("ssh: StdoutPipe after process started")
        }
-       pr, pw := io.Pipe()
-       s.Stdout = pw
-       s.closeAfterWait = append(s.closeAfterWait, pw)
-       return pr, nil
+       s.stdoutpipe = true
+       return s.clientChan.stdout, nil
 }
 
 // StderrPipe returns a pipe that will be connected to the
@@ -417,17 +416,15 @@ func (s *Session) StdoutPipe() (io.ReadCloser, error) {
 // stdout and stderr streams. If the StderrPipe reader is
 // not serviced fast enought it may eventually cause the
 // remote command to block.
-func (s *Session) StderrPipe() (io.ReadCloser, error) {
+func (s *Session) StderrPipe() (io.Reader, error) {
        if s.Stderr != nil {
                return nil, errors.New("ssh: Stderr already set")
        }
        if s.started {
                return nil, errors.New("ssh: StderrPipe after process started")
        }
-       pr, pw := io.Pipe()
-       s.Stderr = pw
-       s.closeAfterWait = append(s.closeAfterWait, pw)
-       return pr, nil
+       s.stderrpipe = true
+       return s.clientChan.stderr, nil
 }
 
 // TODO(dfc) add Output and CombinedOutput helpers
index a28ead087369dfa7007b7d65d660753b1f7d79ef..2882620b0ba3c89c54953429c8e36cb45ca512e9 100644 (file)
@@ -20,7 +20,7 @@ func dial(handler serverType, t *testing.T) *ClientConn {
        serverConfig.PasswordCallback = func(user, pass string) bool {
                return user == "testuser" && pass == string(pw)
        }
-       serverConfig.PubKeyCallback = nil
+       serverConfig.PublicKeyCallback = nil
 
        l, err := Listen("tcp", "127.0.0.1:0", serverConfig)
        if err != nil {
index a85044ace9cecc2c6ee2b3b29ae292de5590989b..bee41eeb0dbc64a2c13fdd7b0d594951aa482223 100644 (file)
@@ -10,6 +10,7 @@ import (
        "io"
        "net"
 )
+
 // Dial initiates a connection to the addr from the remote host.
 // addr is resolved using net.ResolveTCPAddr before connection. 
 // This could allow an observer to observe the DNS name of the 
index 18d76cd6b902769d709afc54dac26871c6918662..809e88cacfa3f448a391ca857ec18a10fef7733c 100644 (file)
@@ -2,13 +2,56 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build linux
+
 package terminal
 
-import "io"
+import (
+       "io"
+       "sync"
+)
+
+// EscapeCodes contains escape sequences that can be written to the terminal in
+// order to achieve different styles of text.
+type EscapeCodes struct {
+       // Foreground colors
+       Black, Red, Green, Yellow, Blue, Magenta, Cyan, White []byte
+
+       // Reset all attributes
+       Reset []byte
+}
+
+var vt100EscapeCodes = EscapeCodes{
+       Black:   []byte{keyEscape, '[', '3', '0', 'm'},
+       Red:     []byte{keyEscape, '[', '3', '1', 'm'},
+       Green:   []byte{keyEscape, '[', '3', '2', 'm'},
+       Yellow:  []byte{keyEscape, '[', '3', '3', 'm'},
+       Blue:    []byte{keyEscape, '[', '3', '4', 'm'},
+       Magenta: []byte{keyEscape, '[', '3', '5', 'm'},
+       Cyan:    []byte{keyEscape, '[', '3', '6', 'm'},
+       White:   []byte{keyEscape, '[', '3', '7', 'm'},
+
+       Reset: []byte{keyEscape, '[', '0', 'm'},
+}
 
 // Terminal contains the state for running a VT100 terminal that is capable of
 // reading lines of input.
 type Terminal struct {
+       // AutoCompleteCallback, if non-null, is called for each keypress
+       // with the full input line and the current position of the cursor.
+       // If it returns a nil newLine, the key press is processed normally.
+       // Otherwise it returns a replacement line and the new cursor position.
+       AutoCompleteCallback func(line []byte, pos, key int) (newLine []byte, newPos int)
+
+       // Escape contains a pointer to the escape codes for this terminal.
+       // It's always a valid pointer, although the escape codes themselves
+       // may be empty if the terminal doesn't support them.
+       Escape *EscapeCodes
+
+       // lock protects the terminal and the state in this object from
+       // concurrent processing of a key press and a Write() call.
+       lock sync.Mutex
+
        c      io.ReadWriter
        prompt string
 
@@ -16,6 +59,8 @@ type Terminal struct {
        line []byte
        // pos is the logical position of the cursor in line
        pos int
+       // echo is true if local echo is enabled
+       echo bool
 
        // cursorX contains the current X value of the cursor where the left
        // edge is 0. cursorY contains the row number where the first row of
@@ -40,10 +85,12 @@ type Terminal struct {
 // "> ").
 func NewTerminal(c io.ReadWriter, prompt string) *Terminal {
        return &Terminal{
+               Escape:     &vt100EscapeCodes,
                c:          c,
                prompt:     prompt,
                termWidth:  80,
                termHeight: 24,
+               echo:       true,
        }
 }
 
@@ -109,18 +156,11 @@ func bytesToKey(b []byte) (int, []byte) {
 
 // queue appends data to the end of t.outBuf
 func (t *Terminal) queue(data []byte) {
-       if len(t.outBuf)+len(data) > cap(t.outBuf) {
-               newOutBuf := make([]byte, len(t.outBuf), 2*(len(t.outBuf)+len(data)))
-               copy(newOutBuf, t.outBuf)
-               t.outBuf = newOutBuf
-       }
-
-       oldLen := len(t.outBuf)
-       t.outBuf = t.outBuf[:len(t.outBuf)+len(data)]
-       copy(t.outBuf[oldLen:], data)
+       t.outBuf = append(t.outBuf, data...)
 }
 
 var eraseUnderCursor = []byte{' ', keyEscape, '[', 'D'}
+var space = []byte{' '}
 
 func isPrintable(key int) bool {
        return key >= 32 && key < 127
@@ -129,6 +169,10 @@ func isPrintable(key int) bool {
 // moveCursorToPos appends data to t.outBuf which will move the cursor to the
 // given, logical position in the text.
 func (t *Terminal) moveCursorToPos(pos int) {
+       if !t.echo {
+               return
+       }
+
        x := len(t.prompt) + pos
        y := x / t.termWidth
        x = x % t.termWidth
@@ -153,6 +197,12 @@ func (t *Terminal) moveCursorToPos(pos int) {
                right = x - t.cursorX
        }
 
+       t.cursorX = x
+       t.cursorY = y
+       t.move(up, down, left, right)
+}
+
+func (t *Terminal) move(up, down, left, right int) {
        movement := make([]byte, 3*(up+down+left+right))
        m := movement
        for i := 0; i < up; i++ {
@@ -180,11 +230,14 @@ func (t *Terminal) moveCursorToPos(pos int) {
                m = m[3:]
        }
 
-       t.cursorX = x
-       t.cursorY = y
        t.queue(movement)
 }
 
+func (t *Terminal) clearLineToRight() {
+       op := []byte{keyEscape, '[', 'K'}
+       t.queue(op)
+}
+
 const maxLineLength = 4096
 
 // handleKey processes the given key and, optionally, returns a line of text
@@ -196,12 +249,15 @@ func (t *Terminal) handleKey(key int) (line string, ok bool) {
                        return
                }
                t.pos--
+               t.moveCursorToPos(t.pos)
 
                copy(t.line[t.pos:], t.line[1+t.pos:])
                t.line = t.line[:len(t.line)-1]
-               t.writeLine(t.line[t.pos:])
-               t.moveCursorToPos(t.pos)
+               if t.echo {
+                       t.writeLine(t.line[t.pos:])
+               }
                t.queue(eraseUnderCursor)
+               t.moveCursorToPos(t.pos)
        case keyAltLeft:
                // move left by a word.
                if t.pos == 0 {
@@ -260,6 +316,25 @@ func (t *Terminal) handleKey(key int) (line string, ok bool) {
                t.cursorY = 0
                t.maxLine = 0
        default:
+               if t.AutoCompleteCallback != nil {
+                       t.lock.Unlock()
+                       newLine, newPos := t.AutoCompleteCallback(t.line, t.pos, key)
+                       t.lock.Lock()
+
+                       if newLine != nil {
+                               if t.echo {
+                                       t.moveCursorToPos(0)
+                                       t.writeLine(newLine)
+                                       for i := len(newLine); i < len(t.line); i++ {
+                                               t.writeLine(space)
+                                       }
+                                       t.moveCursorToPos(newPos)
+                               }
+                               t.line = newLine
+                               t.pos = newPos
+                               return
+                       }
+               }
                if !isPrintable(key) {
                        return
                }
@@ -274,7 +349,9 @@ func (t *Terminal) handleKey(key int) (line string, ok bool) {
                t.line = t.line[:len(t.line)+1]
                copy(t.line[t.pos+1:], t.line[t.pos:])
                t.line[t.pos] = byte(key)
-               t.writeLine(t.line[t.pos:])
+               if t.echo {
+                       t.writeLine(t.line[t.pos:])
+               }
                t.pos++
                t.moveCursorToPos(t.pos)
        }
@@ -283,15 +360,6 @@ func (t *Terminal) handleKey(key int) (line string, ok bool) {
 
 func (t *Terminal) writeLine(line []byte) {
        for len(line) != 0 {
-               if t.cursorX == t.termWidth {
-                       t.queue([]byte("\r\n"))
-                       t.cursorX = 0
-                       t.cursorY++
-                       if t.cursorY > t.maxLine {
-                               t.maxLine = t.cursorY
-                       }
-               }
-
                remainingOnLine := t.termWidth - t.cursorX
                todo := len(line)
                if todo > remainingOnLine {
@@ -300,16 +368,95 @@ func (t *Terminal) writeLine(line []byte) {
                t.queue(line[:todo])
                t.cursorX += todo
                line = line[todo:]
+
+               if t.cursorX == t.termWidth {
+                       t.cursorX = 0
+                       t.cursorY++
+                       if t.cursorY > t.maxLine {
+                               t.maxLine = t.cursorY
+                       }
+               }
        }
 }
 
 func (t *Terminal) Write(buf []byte) (n int, err error) {
-       return t.c.Write(buf)
+       t.lock.Lock()
+       defer t.lock.Unlock()
+
+       if t.cursorX == 0 && t.cursorY == 0 {
+               // This is the easy case: there's nothing on the screen that we
+               // have to move out of the way.
+               return t.c.Write(buf)
+       }
+
+       // We have a prompt and possibly user input on the screen. We
+       // have to clear it first.
+       t.move(0, /* up */ 0, /* down */ t.cursorX, /* left */ 0 /* right */ )
+       t.cursorX = 0
+       t.clearLineToRight()
+
+       for t.cursorY > 0 {
+               t.move(1, /* up */ 0, 0, 0)
+               t.cursorY--
+               t.clearLineToRight()
+       }
+
+       if _, err = t.c.Write(t.outBuf); err != nil {
+               return
+       }
+       t.outBuf = t.outBuf[:0]
+
+       if n, err = t.c.Write(buf); err != nil {
+               return
+       }
+
+       t.queue([]byte(t.prompt))
+       chars := len(t.prompt)
+       if t.echo {
+               t.queue(t.line)
+               chars += len(t.line)
+       }
+       t.cursorX = chars % t.termWidth
+       t.cursorY = chars / t.termWidth
+       t.moveCursorToPos(t.pos)
+
+       if _, err = t.c.Write(t.outBuf); err != nil {
+               return
+       }
+       t.outBuf = t.outBuf[:0]
+       return
+}
+
+// ReadPassword temporarily changes the prompt and reads a password, without
+// echo, from the terminal.
+func (t *Terminal) ReadPassword(prompt string) (line string, err error) {
+       t.lock.Lock()
+       defer t.lock.Unlock()
+
+       oldPrompt := t.prompt
+       t.prompt = prompt
+       t.echo = false
+
+       line, err = t.readLine()
+
+       t.prompt = oldPrompt
+       t.echo = true
+
+       return
 }
 
 // ReadLine returns a line of input from the terminal.
 func (t *Terminal) ReadLine() (line string, err error) {
-       if t.cursorX == 0 {
+       t.lock.Lock()
+       defer t.lock.Unlock()
+
+       return t.readLine()
+}
+
+func (t *Terminal) readLine() (line string, err error) {
+       // t.lock must be held at this point
+
+       if t.cursorX == 0 && t.cursorY == 0 {
                t.writeLine([]byte(t.prompt))
                t.c.Write(t.outBuf)
                t.outBuf = t.outBuf[:0]
@@ -320,7 +467,11 @@ func (t *Terminal) ReadLine() (line string, err error) {
                // containing a partial key sequence
                readBuf := t.inBuf[len(t.remainder):]
                var n int
+
+               t.lock.Unlock()
                n, err = t.c.Read(readBuf)
+               t.lock.Lock()
+
                if err != nil {
                        return
                }
@@ -358,5 +509,8 @@ func (t *Terminal) ReadLine() (line string, err error) {
 }
 
 func (t *Terminal) SetSize(width, height int) {
+       t.lock.Lock()
+       defer t.lock.Unlock()
+
        t.termWidth, t.termHeight = width, height
 }
index a2197210e2a8d4da5720b2c797afccd21156011d..75628f695e989e41fe5f6e8d48b24955f975dcfe 100644 (file)
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build linux
+
 package terminal
 
 import (
index 030356738697d986750f1805cbe33aea9a878685..a5bbfca3b46b4e565c785ee1b6afe1dd11178adf 100644 (file)
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build linux
+
 // Package terminal provides support functions for dealing with terminals, as
 // commonly found on UNIX systems.
 //
@@ -9,7 +11,7 @@
 //
 //     oldState, err := terminal.MakeRaw(0)
 //     if err != nil {
-//             panic(err.String())
+//             panic(err)
 //     }
 //     defer terminal.Restore(0, oldState)
 package terminal
@@ -17,6 +19,7 @@ package terminal
 import (
        "io"
        "syscall"
+       "unsafe"
 )
 
 // State contains the state of a terminal.
@@ -57,6 +60,18 @@ func Restore(fd int, state *State) error {
        return err
 }
 
+func ioctl(int, int, unsafe.Pointer) int __asm__("ioctl")
+
+// GetSize returns the dimensions of the given terminal.
+func GetSize(fd int) (width, height int, err error) {
+       var dimensions [4]uint16
+
+       if ioctl(fd, syscall.TIOCGWINSZ, unsafe.Pointer(&dimensions)) < 0 {
+               return -1, -1, syscall.GetErrno()
+       }
+       return int(dimensions[1]), int(dimensions[0]), nil
+}
+
 // ReadPassword reads a line of input from a terminal without local echo.  This
 // is commonly used for inputting passwords and other sensitive data. The slice
 // returned does not include the \n.
index d47ffd139216bc09abbbe5273b5768f4bac65f77..a6e3a6a8fb75e2428bda27cedda9dfd5bbe1d719 100644 (file)
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build windows
+
 // Package winfsnotify allows the user to receive
 // file system event notifications on Windows.
 package winfsnotify
index b9c43d9c006705bb7a1efc1cd80973cdae455ff1..59ac1624a265c81b319f6eccb8a7cd420be11914 100644 (file)
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build windows
+
 package winfsnotify
 
 import (
index d58421bcfa740665255de8113261bfdf310d331f..3b79873fa2bda394dda1456f83c074cbae980030 100644 (file)
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build windows
+
 package main
 
 import (
index 24f3dd4d723e783d58d13fffd67d8c916b825d6c..f876088e91fc893dac2ea6b634301358aad0fbf6 100644 (file)
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build windows
+
 package main
 
 import (
index b062ca3372e1bdca2dd19bcd8c3d918970c757fb..5666c6de5308f95d424ea21f8f5fb2999e4e150b 100644 (file)
@@ -1,3 +1,4 @@
+// +build windows
 // mksyscall_windows.pl winapi.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
index d7fe296f09575ef384b826c82ce1cfacade2f377..d34a4f8fd2d368c2ce81f4497d26ee69be6c4d45 100644 (file)
@@ -506,78 +506,42 @@ func BenchmarkSprintfFloat(b *testing.B) {
        }
 }
 
+var mallocBuf bytes.Buffer
+
+var mallocTest = []struct {
+       count int
+       desc  string
+       fn    func()
+}{
+       {0, `Sprintf("")`, func() { Sprintf("") }},
+       {1, `Sprintf("xxx")`, func() { Sprintf("xxx") }},
+       {1, `Sprintf("%x")`, func() { Sprintf("%x", 7) }},
+       {2, `Sprintf("%s")`, func() { Sprintf("%s", "hello") }},
+       {1, `Sprintf("%x %x")`, func() { Sprintf("%x", 7, 112) }},
+       {1, `Sprintf("%g")`, func() { Sprintf("%g", 3.14159) }},
+       {0, `Fprintf(buf, "%x %x %x")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%x %x %x", 7, 8, 9) }},
+       {1, `Fprintf(buf, "%s")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%s", "hello") }},
+}
+
+var _ bytes.Buffer
+
 func TestCountMallocs(t *testing.T) {
        if testing.Short() {
                return
        }
-       const N = 100
-       runtime.UpdateMemStats()
-       mallocs := 0 - runtime.MemStats.Mallocs
-       for i := 0; i < N; i++ {
-               Sprintf("")
-       }
-       runtime.UpdateMemStats()
-       mallocs += runtime.MemStats.Mallocs
-       Printf("mallocs per Sprintf(\"\"): %d\n", mallocs/N)
-       runtime.UpdateMemStats()
-       mallocs = 0 - runtime.MemStats.Mallocs
-       for i := 0; i < N; i++ {
-               Sprintf("xxx")
-       }
-       runtime.UpdateMemStats()
-       mallocs += runtime.MemStats.Mallocs
-       Printf("mallocs per Sprintf(\"xxx\"): %d\n", mallocs/N)
-       runtime.UpdateMemStats()
-       mallocs = 0 - runtime.MemStats.Mallocs
-       for i := 0; i < N; i++ {
-               Sprintf("%x", i)
-       }
-       runtime.UpdateMemStats()
-       mallocs += runtime.MemStats.Mallocs
-       Printf("mallocs per Sprintf(\"%%x\"): %d\n", mallocs/N)
-       runtime.UpdateMemStats()
-       mallocs = 0 - runtime.MemStats.Mallocs
-       for i := 0; i < N; i++ {
-               Sprintf("%s", "hello")
-       }
-       runtime.UpdateMemStats()
-       mallocs += runtime.MemStats.Mallocs
-       Printf("mallocs per Sprintf(\"%%s\"): %d\n", mallocs/N)
-       runtime.UpdateMemStats()
-       mallocs = 0 - runtime.MemStats.Mallocs
-       for i := 0; i < N; i++ {
-               Sprintf("%x %x", i, i)
-       }
-       runtime.UpdateMemStats()
-       mallocs += runtime.MemStats.Mallocs
-       Printf("mallocs per Sprintf(\"%%x %%x\"): %d\n", mallocs/N)
-       runtime.UpdateMemStats()
-       mallocs = 0 - runtime.MemStats.Mallocs
-       for i := 0; i < N; i++ {
-               Sprintf("%g", 3.14159)
-       }
-       runtime.UpdateMemStats()
-       mallocs += runtime.MemStats.Mallocs
-       Printf("mallocs per Sprintf(\"%%g\"): %d\n", mallocs/N)
-       buf := new(bytes.Buffer)
-       runtime.UpdateMemStats()
-       mallocs = 0 - runtime.MemStats.Mallocs
-       for i := 0; i < N; i++ {
-               buf.Reset()
-               Fprintf(buf, "%x %x %x", i, i, i)
-       }
-       runtime.UpdateMemStats()
-       mallocs += runtime.MemStats.Mallocs
-       Printf("mallocs per Fprintf(buf, \"%%x %%x %%x\"): %d\n", mallocs/N)
-       runtime.UpdateMemStats()
-       mallocs = 0 - runtime.MemStats.Mallocs
-       for i := 0; i < N; i++ {
-               buf.Reset()
-               Fprintf(buf, "%s", "hello")
+       for _, mt := range mallocTest {
+               const N = 100
+               runtime.UpdateMemStats()
+               mallocs := 0 - runtime.MemStats.Mallocs
+               for i := 0; i < N; i++ {
+                       mt.fn()
+               }
+               runtime.UpdateMemStats()
+               mallocs += runtime.MemStats.Mallocs
+               if mallocs/N != uint64(mt.count) {
+                       t.Errorf("%s: expected %d mallocs, got %d", mt.desc, mt.count, mallocs/N)
+               }
        }
-       runtime.UpdateMemStats()
-       mallocs += runtime.MemStats.Mallocs
-       Printf("mallocs per Fprintf(buf, \"%%s\"): %d\n", mallocs/N)
 }
 
 type flagPrinter struct{}
index 5f62c067f06a716bd075bf0f39464fb0ecd2c361..78d9e998b1fe0c32c5d600c02ac6fe114c15ba9d 100644 (file)
@@ -154,12 +154,17 @@ func putint(buf []byte, base, val uint64, digits string) int {
        return i - 1
 }
 
+var (
+       trueBytes  = []byte("true")
+       falseBytes = []byte("false")
+)
+
 // fmt_boolean formats a boolean.
 func (f *fmt) fmt_boolean(v bool) {
        if v {
-               f.padString("true")
+               f.pad(trueBytes)
        } else {
-               f.padString("false")
+               f.pad(falseBytes)
        }
 }
 
@@ -283,31 +288,18 @@ func (f *fmt) fmt_s(s string) {
 }
 
 // fmt_sx formats a string as a hexadecimal encoding of its bytes.
-func (f *fmt) fmt_sx(s string) {
-       t := ""
+func (f *fmt) fmt_sx(s, digits string) {
+       // TODO: Avoid buffer by pre-padding.
+       var b bytes.Buffer
        for i := 0; i < len(s); i++ {
                if i > 0 && f.space {
-                       t += " "
+                       b.WriteByte(' ')
                }
                v := s[i]
-               t += string(ldigits[v>>4])
-               t += string(ldigits[v&0xF])
+               b.WriteByte(digits[v>>4])
+               b.WriteByte(digits[v&0xF])
        }
-       f.padString(t)
-}
-
-// fmt_sX formats a string as an uppercase hexadecimal encoding of its bytes.
-func (f *fmt) fmt_sX(s string) {
-       t := ""
-       for i := 0; i < len(s); i++ {
-               if i > 0 && f.space {
-                       t += " "
-               }
-               v := s[i]
-               t += string(udigits[v>>4])
-               t += string(udigits[v&0xF])
-       }
-       f.padString(t)
+       f.pad(b.Bytes())
 }
 
 // fmt_q formats a string as a double-quoted, escaped Go string constant.
@@ -329,13 +321,13 @@ func (f *fmt) fmt_q(s string) {
 // fmt_qc formats the integer as a single-quoted, escaped Go character constant.
 // If the character is not valid Unicode, it will print '\ufffd'.
 func (f *fmt) fmt_qc(c int64) {
-       var quoted string
+       var quoted []byte
        if f.plus {
-               quoted = strconv.QuoteRuneToASCII(rune(c))
+               quoted = strconv.AppendQuoteRuneToASCII(f.intbuf[0:0], rune(c))
        } else {
-               quoted = strconv.QuoteRune(rune(c))
+               quoted = strconv.AppendQuoteRune(f.intbuf[0:0], rune(c))
        }
-       f.padString(quoted)
+       f.pad(quoted)
 }
 
 // floating-point
@@ -347,57 +339,70 @@ func doPrec(f *fmt, def int) int {
        return def
 }
 
-// Add a plus sign or space to the floating-point string representation if missing and required.
-func (f *fmt) plusSpace(s string) {
-       if s[0] != '-' {
+// formatFloat formats a float64; it is an efficient equivalent to  f.pad(strconv.FormatFloat()...).
+func (f *fmt) formatFloat(v float64, verb byte, prec, n int) {
+       // We leave one byte at the beginning of f.intbuf for a sign if needed,
+       // and make it a space, which we might be able to use.
+       f.intbuf[0] = ' '
+       slice := strconv.AppendFloat(f.intbuf[0:1], v, verb, prec, n)
+       // Add a plus sign or space to the floating-point string representation if missing and required.
+       // The formatted number starts at slice[1].
+       switch slice[1] {
+       case '-', '+':
+               // We're set; drop the leading space.
+               slice = slice[1:]
+       default:
+               // There's no sign, but we might need one.
                if f.plus {
-                       s = "+" + s
+                       slice[0] = '+'
                } else if f.space {
-                       s = " " + s
+                       // space is already there
+               } else {
+                       slice = slice[1:]
                }
        }
-       f.padString(s)
+       f.pad(slice)
 }
 
 // fmt_e64 formats a float64 in the form -1.23e+12.
-func (f *fmt) fmt_e64(v float64) { f.plusSpace(strconv.FormatFloat(v, 'e', doPrec(f, 6), 64)) }
+func (f *fmt) fmt_e64(v float64) { f.formatFloat(v, 'e', doPrec(f, 6), 64) }
 
 // fmt_E64 formats a float64 in the form -1.23E+12.
-func (f *fmt) fmt_E64(v float64) { f.plusSpace(strconv.FormatFloat(v, 'E', doPrec(f, 6), 64)) }
+func (f *fmt) fmt_E64(v float64) { f.formatFloat(v, 'E', doPrec(f, 6), 64) }
 
 // fmt_f64 formats a float64 in the form -1.23.
-func (f *fmt) fmt_f64(v float64) { f.plusSpace(strconv.FormatFloat(v, 'f', doPrec(f, 6), 64)) }
+func (f *fmt) fmt_f64(v float64) { f.formatFloat(v, 'f', doPrec(f, 6), 64) }
 
 // fmt_g64 formats a float64 in the 'f' or 'e' form according to size.
-func (f *fmt) fmt_g64(v float64) { f.plusSpace(strconv.FormatFloat(v, 'g', doPrec(f, -1), 64)) }
+func (f *fmt) fmt_g64(v float64) { f.formatFloat(v, 'g', doPrec(f, -1), 64) }
 
 // fmt_g64 formats a float64 in the 'f' or 'E' form according to size.
-func (f *fmt) fmt_G64(v float64) { f.plusSpace(strconv.FormatFloat(v, 'G', doPrec(f, -1), 64)) }
+func (f *fmt) fmt_G64(v float64) { f.formatFloat(v, 'G', doPrec(f, -1), 64) }
 
 // fmt_fb64 formats a float64 in the form -123p3 (exponent is power of 2).
-func (f *fmt) fmt_fb64(v float64) { f.plusSpace(strconv.FormatFloat(v, 'b', 0, 64)) }
+func (f *fmt) fmt_fb64(v float64) { f.formatFloat(v, 'b', 0, 64) }
 
 // float32
 // cannot defer to float64 versions
 // because it will get rounding wrong in corner cases.
 
 // fmt_e32 formats a float32 in the form -1.23e+12.
-func (f *fmt) fmt_e32(v float32) { f.plusSpace(strconv.FormatFloat(float64(v), 'e', doPrec(f, 6), 32)) }
+func (f *fmt) fmt_e32(v float32) { f.formatFloat(float64(v), 'e', doPrec(f, 6), 32) }
 
 // fmt_E32 formats a float32 in the form -1.23E+12.
-func (f *fmt) fmt_E32(v float32) { f.plusSpace(strconv.FormatFloat(float64(v), 'E', doPrec(f, 6), 32)) }
+func (f *fmt) fmt_E32(v float32) { f.formatFloat(float64(v), 'E', doPrec(f, 6), 32) }
 
 // fmt_f32 formats a float32 in the form -1.23.
-func (f *fmt) fmt_f32(v float32) { f.plusSpace(strconv.FormatFloat(float64(v), 'f', doPrec(f, 6), 32)) }
+func (f *fmt) fmt_f32(v float32) { f.formatFloat(float64(v), 'f', doPrec(f, 6), 32) }
 
 // fmt_g32 formats a float32 in the 'f' or 'e' form according to size.
-func (f *fmt) fmt_g32(v float32) { f.plusSpace(strconv.FormatFloat(float64(v), 'g', doPrec(f, -1), 32)) }
+func (f *fmt) fmt_g32(v float32) { f.formatFloat(float64(v), 'g', doPrec(f, -1), 32) }
 
 // fmt_G32 formats a float32 in the 'f' or 'E' form according to size.
-func (f *fmt) fmt_G32(v float32) { f.plusSpace(strconv.FormatFloat(float64(v), 'G', doPrec(f, -1), 32)) }
+func (f *fmt) fmt_G32(v float32) { f.formatFloat(float64(v), 'G', doPrec(f, -1), 32) }
 
 // fmt_fb32 formats a float32 in the form -123p3 (exponent is power of 2).
-func (f *fmt) fmt_fb32(v float32) { f.padString(strconv.FormatFloat(float64(v), 'b', 0, 32)) }
+func (f *fmt) fmt_fb32(v float32) { f.formatFloat(float64(v), 'b', 0, 32) }
 
 // fmt_c64 formats a complex64 according to the verb.
 func (f *fmt) fmt_c64(v complex64, verb rune) {
index 9f157daaee01d043890900818df3056f4d9d1534..3b7d3464e209a215e4d65fa7e88bca721e218c21 100644 (file)
@@ -503,9 +503,9 @@ func (p *pp) fmtString(v string, verb rune, goSyntax bool) {
        case 's':
                p.fmt.fmt_s(v)
        case 'x':
-               p.fmt.fmt_sx(v)
+               p.fmt.fmt_sx(v, ldigits)
        case 'X':
-               p.fmt.fmt_sX(v)
+               p.fmt.fmt_sx(v, udigits)
        case 'q':
                p.fmt.fmt_q(v)
        default:
@@ -542,9 +542,9 @@ func (p *pp) fmtBytes(v []byte, verb rune, goSyntax bool, depth int) {
        case 's':
                p.fmt.fmt_s(s)
        case 'x':
-               p.fmt.fmt_sx(s)
+               p.fmt.fmt_sx(s, ldigits)
        case 'X':
-               p.fmt.fmt_sX(s)
+               p.fmt.fmt_sx(s, udigits)
        case 'q':
                p.fmt.fmt_q(s)
        default:
index 92e3669808121ab704e58afcbccb2de0266aec12..fbe4779671ec8fc67b857d89eae1c6e6cb01422a 100644 (file)
@@ -80,7 +80,7 @@ func (s *Scope) String() string {
 type Object struct {
        Kind ObjKind
        Name string      // declared name
-       Decl interface{} // corresponding Field, XxxSpec, FuncDecl, or LabeledStmt; or nil
+       Decl interface{} // corresponding Field, XxxSpec, FuncDecl, LabeledStmt, or AssignStmt; or nil
        Data interface{} // object-specific data; or nil
        Type interface{} // place holder for type information; may be nil
 }
@@ -125,6 +125,12 @@ func (obj *Object) Pos() token.Pos {
                if d.Label.Name == name {
                        return d.Label.Pos()
                }
+       case *AssignStmt:
+               for _, x := range d.Lhs {
+                       if ident, isIdent := x.(*Ident); isIdent && ident.Name == name {
+                               return ident.Pos()
+                       }
+               }
        }
        return token.NoPos
 }
index e22a49aa3d6179d0b202046f7944da8b901a7300..fd4030632a9d8dc77cc9e898fdc6d3ef1f756501 100644 (file)
@@ -46,8 +46,9 @@ var buildPkgs = []struct {
        {
                "go/build/cgotest",
                &DirInfo{
-                       CgoFiles:    []string{"cgotest.go"},
+                       CgoFiles:    ifCgo([]string{"cgotest.go"}),
                        CFiles:      []string{"cgotest.c"},
+                       HFiles:      []string{"cgotest.h"},
                        Imports:     []string{"C", "unsafe"},
                        TestImports: []string{},
                        Package:     "cgotest",
@@ -55,6 +56,13 @@ var buildPkgs = []struct {
        },
 }
 
+func ifCgo(x []string) []string {
+       if DefaultContext.CgoEnabled {
+               return x
+       }
+       return nil
+}
+
 const cmdtestOutput = "3"
 
 func TestBuild(t *testing.T) {
@@ -71,6 +79,10 @@ func TestBuild(t *testing.T) {
                        continue
                }
 
+               if tt.dir == "go/build/cgotest" && len(info.CgoFiles) == 0 {
+                       continue
+               }
+
                s, err := Build(tree, tt.dir, info)
                if err != nil {
                        t.Errorf("Build(%#q): %v", tt.dir, err)
index 2c89224fd4bb0056a557c0bdf176bea6622d3ea4..265261f22eaaac2c71c7f43290a343a7b765f423 100644 (file)
@@ -26,9 +26,9 @@ import (
 
 // A Context specifies the supporting context for a build.
 type Context struct {
-       GOARCH string // target architecture
-       GOOS   string // target operating system
-       // TODO(rsc,adg): GOPATH
+       GOARCH     string // target architecture
+       GOOS       string // target operating system
+       CgoEnabled bool   // whether cgo can be used
 
        // By default, ScanDir uses the operating system's
        // file system calls to read directories and files.
@@ -75,9 +75,36 @@ func (ctxt *Context) readFile(dir, file string) (string, []byte, error) {
 // The DefaultContext is the default Context for builds.
 // It uses the GOARCH and GOOS environment variables
 // if set, or else the compiled code's GOARCH and GOOS.
-var DefaultContext = Context{
-       GOARCH: envOr("GOARCH", runtime.GOARCH),
-       GOOS:   envOr("GOOS", runtime.GOOS),
+var DefaultContext = defaultContext()
+
+var cgoEnabled = map[string]bool{
+       "darwin/386":    true,
+       "darwin/amd64":  true,
+       "linux/386":     true,
+       "linux/amd64":   true,
+       "freebsd/386":   true,
+       "freebsd/amd64": true,
+       "windows/386":   true,
+       "windows/amd64": true,
+}
+
+func defaultContext() Context {
+       var c Context
+
+       c.GOARCH = envOr("GOARCH", runtime.GOARCH)
+       c.GOOS = envOr("GOOS", runtime.GOOS)
+
+       s := os.Getenv("CGO_ENABLED")
+       switch s {
+       case "1":
+               c.CgoEnabled = true
+       case "0":
+               c.CgoEnabled = false
+       default:
+               c.CgoEnabled = cgoEnabled[c.GOOS+"/"+c.GOARCH]
+       }
+
+       return c
 }
 
 func envOr(name, def string) string {
@@ -96,8 +123,9 @@ type DirInfo struct {
 
        // Source files
        GoFiles  []string // .go files in dir (excluding CgoFiles)
+       HFiles   []string // .h files in dir
        CFiles   []string // .c files in dir
-       SFiles   []string // .s files in dir
+       SFiles   []string // .s (and, when using cgo, .S files in dir)
        CgoFiles []string // .go files that import "C"
 
        // Cgo directives
@@ -135,6 +163,7 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {
                return nil, err
        }
 
+       var Sfiles []string // files with ".S" (capital S)
        var di DirInfo
        imported := make(map[string]bool)
        testImported := make(map[string]bool)
@@ -154,7 +183,7 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {
 
                ext := path.Ext(name)
                switch ext {
-               case ".go", ".c", ".s":
+               case ".go", ".c", ".s", ".h", ".S":
                        // tentatively okay
                default:
                        // skip
@@ -175,9 +204,15 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {
                case ".c":
                        di.CFiles = append(di.CFiles, name)
                        continue
+               case ".h":
+                       di.HFiles = append(di.HFiles, name)
+                       continue
                case ".s":
                        di.SFiles = append(di.SFiles, name)
                        continue
+               case ".S":
+                       Sfiles = append(Sfiles, name)
+                       continue
                }
 
                pf, err := parser.ParseFile(fset, filename, data, parser.ImportsOnly|parser.ParseComments)
@@ -256,7 +291,9 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {
                        }
                }
                if isCgo {
-                       di.CgoFiles = append(di.CgoFiles, name)
+                       if ctxt.CgoEnabled {
+                               di.CgoFiles = append(di.CgoFiles, name)
+                       }
                } else if isTest {
                        if pkg == string(pf.Name.Name) {
                                di.TestGoFiles = append(di.TestGoFiles, name)
@@ -282,6 +319,15 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {
                di.TestImports[i] = p
                i++
        }
+
+       // add the .S files only if we are using cgo
+       // (which means gcc will compile them).
+       // The standard assemblers expect .s files.
+       if len(di.CgoFiles) > 0 {
+               di.SFiles = append(di.SFiles, Sfiles...)
+               sort.Strings(di.SFiles)
+       }
+
        // File name lists are sorted because ReadDir sorts.
        sort.Strings(di.Imports)
        sort.Strings(di.TestImports)
@@ -289,7 +335,6 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {
 }
 
 var slashslash = []byte("//")
-var plusBuild = []byte("+build")
 
 // shouldBuild reports whether it is okay to use this file,
 // The rule is that in the file's leading run of // comments
@@ -510,14 +555,22 @@ func splitQuoted(s string) (r []string, err error) {
 //
 //     $GOOS
 //     $GOARCH
-//     $GOOS/$GOARCH
+//     cgo (if cgo is enabled)
+//     nocgo (if cgo is disabled)
+//     a slash-separated list of any of these
 //
 func (ctxt *Context) matchOSArch(name string) bool {
+       if ctxt.CgoEnabled && name == "cgo" {
+               return true
+       }
+       if !ctxt.CgoEnabled && name == "nocgo" {
+               return true
+       }
        if name == ctxt.GOOS || name == ctxt.GOARCH {
                return true
        }
        i := strings.Index(name, "/")
-       return i >= 0 && name[:i] == ctxt.GOOS && name[i+1:] == ctxt.GOARCH
+       return i >= 0 && ctxt.matchOSArch(name[:i]) && ctxt.matchOSArch(name[i+1:])
 }
 
 // goodOSArchFile returns false if the name contains a $GOOS or $GOARCH
index 91d6c430a9d6e398900314fdd7de6b4c4ee5c3a8..7a281800c2828afe57bdbe3cde1286b49f804d30 100644 (file)
@@ -57,7 +57,7 @@ func (t *Tree) PkgDir() string {
 func (t *Tree) BinDir() string {
        if t.Goroot {
                if gobin := os.Getenv("GOBIN"); gobin != "" {
-                       return gobin
+                       return filepath.Clean(gobin)
                }
        }
        return filepath.Join(t.Path, "bin")
@@ -85,8 +85,8 @@ func (t *Tree) HasPkg(pkg string) bool {
 }
 
 var (
-       ErrNotFound     = errors.New("go/build: package could not be found locally")
-       ErrTreeNotFound = errors.New("go/build: no valid GOROOT or GOPATH could be found")
+       ErrNotFound     = errors.New("package could not be found locally")
+       ErrTreeNotFound = errors.New("no valid GOROOT or GOPATH could be found")
 )
 
 // FindTree takes an import or filesystem path and returns the
@@ -151,7 +151,7 @@ func init() {
        root := runtime.GOROOT()
        t, err := newTree(root)
        if err != nil {
-               log.Printf("go/build: invalid GOROOT %q: %v", root, err)
+               log.Printf("invalid GOROOT %q: %v", root, err)
        } else {
                t.Goroot = true
                Path = []*Tree{t}
@@ -163,7 +163,7 @@ func init() {
                }
                t, err := newTree(p)
                if err != nil {
-                       log.Printf("go/build: invalid GOPATH %q: %v", p, err)
+                       log.Printf("invalid GOPATH %q: %v", p, err)
                        continue
                }
                Path = append(Path, t)
index 9174864339117c7f7c46823ea09bec51da4a09bf..1bb22416c78ad9f81a5103a50cf145c83cc94a99 100644 (file)
@@ -13,17 +13,32 @@ import (
 )
 
 // ----------------------------------------------------------------------------
+// Collection of documentation info
 
-type typeDoc struct {
+// embeddedType describes the type of an anonymous field.
+//
+type embeddedType struct {
+       typ *typeInfo // the corresponding base type
+       ptr bool      // if set, the anonymous field type is a pointer
+}
+
+type typeInfo struct {
        // len(decl.Specs) == 1, and the element type is *ast.TypeSpec
        // if the type declaration hasn't been seen yet, decl is nil
-       decl *ast.GenDecl
-       // values, factory functions, and methods associated with the type
+       decl     *ast.GenDecl
+       embedded []embeddedType
+       forward  *TypeDoc // forward link to processed type documentation
+
+       // declarations associated with the type
        values    []*ast.GenDecl // consts and vars
        factories map[string]*ast.FuncDecl
        methods   map[string]*ast.FuncDecl
 }
 
+func (info *typeInfo) addEmbeddedType(embedded *typeInfo, isPtr bool) {
+       info.embedded = append(info.embedded, embeddedType{embedded, isPtr})
+}
+
 // docReader accumulates documentation for a single package.
 // It modifies the AST: Comments (declaration documentation)
 // that have been collected by the DocReader are set to nil
@@ -32,17 +47,19 @@ type typeDoc struct {
 // printing the corresponding AST node).
 //
 type docReader struct {
-       doc     *ast.CommentGroup // package documentation, if any
-       pkgName string
-       values  []*ast.GenDecl // consts and vars
-       types   map[string]*typeDoc
-       funcs   map[string]*ast.FuncDecl
-       bugs    []*ast.CommentGroup
+       doc      *ast.CommentGroup // package documentation, if any
+       pkgName  string
+       values   []*ast.GenDecl // consts and vars
+       types    map[string]*typeInfo
+       embedded map[string]*typeInfo // embedded types, possibly not exported
+       funcs    map[string]*ast.FuncDecl
+       bugs     []*ast.CommentGroup
 }
 
 func (doc *docReader) init(pkgName string) {
        doc.pkgName = pkgName
-       doc.types = make(map[string]*typeDoc)
+       doc.types = make(map[string]*typeInfo)
+       doc.embedded = make(map[string]*typeInfo)
        doc.funcs = make(map[string]*ast.FuncDecl)
 }
 
@@ -52,56 +69,40 @@ func (doc *docReader) addDoc(comments *ast.CommentGroup) {
                doc.doc = comments
                return
        }
-
        // More than one package comment: Usually there will be only
        // one file with a package comment, but it's better to collect
        // all comments than drop them on the floor.
-       // (This code isn't particularly clever - no amortized doubling is
-       // used - but this situation occurs rarely and is not time-critical.)
-       n1 := len(doc.doc.List)
-       n2 := len(comments.List)
-       list := make([]*ast.Comment, n1+1+n2) // + 1 for separator line
-       copy(list, doc.doc.List)
-       list[n1] = &ast.Comment{token.NoPos, "//"} // separator line
-       copy(list[n1+1:], comments.List)
-       doc.doc = &ast.CommentGroup{list}
-}
-
-func (doc *docReader) addType(decl *ast.GenDecl) {
-       spec := decl.Specs[0].(*ast.TypeSpec)
-       typ := doc.lookupTypeDoc(spec.Name.Name)
-       // typ should always be != nil since declared types
-       // are always named - be conservative and check
-       if typ != nil {
-               // a type should be added at most once, so typ.decl
-               // should be nil - if it isn't, simply overwrite it
-               typ.decl = decl
-       }
+       blankComment := &ast.Comment{token.NoPos, "//"}
+       list := append(doc.doc.List, blankComment)
+       doc.doc.List = append(list, comments.List...)
 }
 
-func (doc *docReader) lookupTypeDoc(name string) *typeDoc {
-       if name == "" {
+func (doc *docReader) lookupTypeInfo(name string) *typeInfo {
+       if name == "" || name == "_" {
                return nil // no type docs for anonymous types
        }
-       if tdoc, found := doc.types[name]; found {
-               return tdoc
+       if info, found := doc.types[name]; found {
+               return info
        }
        // type wasn't found - add one without declaration
-       tdoc := &typeDoc{nil, nil, make(map[string]*ast.FuncDecl), make(map[string]*ast.FuncDecl)}
-       doc.types[name] = tdoc
-       return tdoc
+       info := &typeInfo{
+               factories: make(map[string]*ast.FuncDecl),
+               methods:   make(map[string]*ast.FuncDecl),
+       }
+       doc.types[name] = info
+       return info
 }
 
-func baseTypeName(typ ast.Expr) string {
+func baseTypeName(typ ast.Expr, allTypes bool) string {
        switch t := typ.(type) {
        case *ast.Ident:
                // if the type is not exported, the effect to
                // a client is as if there were no type name
-               if t.IsExported() {
+               if t.IsExported() || allTypes {
                        return t.Name
                }
        case *ast.StarExpr:
-               return baseTypeName(t.X)
+               return baseTypeName(t.X, allTypes)
        }
        return ""
 }
@@ -120,7 +121,7 @@ func (doc *docReader) addValue(decl *ast.GenDecl) {
                        switch {
                        case v.Type != nil:
                                // a type is present; determine its name
-                               name = baseTypeName(v.Type)
+                               name = baseTypeName(v.Type, false)
                        case decl.Tok == token.CONST:
                                // no type is present but we have a constant declaration;
                                // use the previous type name (w/o more type information
@@ -148,7 +149,7 @@ func (doc *docReader) addValue(decl *ast.GenDecl) {
        values := &doc.values
        if domName != "" && domFreq >= int(float64(len(decl.Specs))*threshold) {
                // typed entries are sufficiently frequent
-               typ := doc.lookupTypeDoc(domName)
+               typ := doc.lookupTypeInfo(domName)
                if typ != nil {
                        values = &typ.values // associate with that type
                }
@@ -175,10 +176,13 @@ func setFunc(table map[string]*ast.FuncDecl, f *ast.FuncDecl) {
 }
 
 func (doc *docReader) addFunc(fun *ast.FuncDecl) {
+       // strip function body
+       fun.Body = nil
+
        // determine if it should be associated with a type
        if fun.Recv != nil {
                // method
-               typ := doc.lookupTypeDoc(baseTypeName(fun.Recv.List[0].Type))
+               typ := doc.lookupTypeInfo(baseTypeName(fun.Recv.List[0].Type, false))
                if typ != nil {
                        // exported receiver type
                        setFunc(typ.methods, fun)
@@ -199,8 +203,8 @@ func (doc *docReader) addFunc(fun *ast.FuncDecl) {
                        // exactly one (named or anonymous) result associated
                        // with the first type in result signature (there may
                        // be more than one result)
-                       tname := baseTypeName(res.Type)
-                       typ := doc.lookupTypeDoc(tname)
+                       tname := baseTypeName(res.Type, false)
+                       typ := doc.lookupTypeInfo(tname)
                        if typ != nil {
                                // named and exported result type
                                setFunc(typ.factories, fun)
@@ -224,10 +228,17 @@ func (doc *docReader) addDecl(decl ast.Decl) {
                        case token.TYPE:
                                // types are handled individually
                                for _, spec := range d.Specs {
-                                       // make a (fake) GenDecl node for this TypeSpec
+                                       tspec := spec.(*ast.TypeSpec)
+                                       // add the type to the documentation
+                                       info := doc.lookupTypeInfo(tspec.Name.Name)
+                                       if info == nil {
+                                               continue // no name - ignore the type
+                                       }
+                                       // Make a (fake) GenDecl node for this TypeSpec
                                        // (we need to do this here - as opposed to just
                                        // for printing - so we don't lose the GenDecl
-                                       // documentation)
+                                       // documentation). Since a new GenDecl node is
+                                       // created, there's no need to nil out d.Doc.
                                        //
                                        // TODO(gri): Consider just collecting the TypeSpec
                                        // node (and copy in the GenDecl.doc if there is no
@@ -235,8 +246,32 @@ func (doc *docReader) addDecl(decl ast.Decl) {
                                        // makeTypeDocs below). Simpler data structures, but
                                        // would lose GenDecl documentation if the TypeSpec
                                        // has documentation as well.
-                                       doc.addType(&ast.GenDecl{d.Doc, d.Pos(), token.TYPE, token.NoPos, []ast.Spec{spec}, token.NoPos})
-                                       // A new GenDecl node is created, no need to nil out d.Doc.
+                                       fake := &ast.GenDecl{d.Doc, d.Pos(), token.TYPE, token.NoPos,
+                                               []ast.Spec{tspec}, token.NoPos}
+                                       // A type should be added at most once, so info.decl
+                                       // should be nil - if it isn't, simply overwrite it.
+                                       info.decl = fake
+                                       // Look for anonymous fields that might contribute methods.
+                                       var fields *ast.FieldList
+                                       switch typ := spec.(*ast.TypeSpec).Type.(type) {
+                                       case *ast.StructType:
+                                               fields = typ.Fields
+                                       case *ast.InterfaceType:
+                                               fields = typ.Methods
+                                       }
+                                       if fields != nil {
+                                               for _, field := range fields.List {
+                                                       if len(field.Names) == 0 {
+                                                               // anonymous field - add corresponding type
+                                                               // to the info and collect it in doc
+                                                               name := baseTypeName(field.Type, true)
+                                                               if embedded := doc.lookupTypeInfo(name); embedded != nil {
+                                                                       _, ptr := field.Type.(*ast.StarExpr)
+                                                                       info.addEmbeddedType(embedded, ptr)
+                                                               }
+                                                       }
+                                               }
+                                       }
                                }
                        }
                }
@@ -285,19 +320,15 @@ func (doc *docReader) addFile(src *ast.File) {
        src.Comments = nil // consumed unassociated comments - remove from ast.File node
 }
 
-func NewFileDoc(file *ast.File) *PackageDoc {
-       var r docReader
-       r.init(file.Name.Name)
-       r.addFile(file)
-       return r.newDoc("", nil)
-}
-
-func NewPackageDoc(pkg *ast.Package, importpath string) *PackageDoc {
+func NewPackageDoc(pkg *ast.Package, importpath string, exportsOnly bool) *PackageDoc {
        var r docReader
        r.init(pkg.Name)
        filenames := make([]string, len(pkg.Files))
        i := 0
        for filename, f := range pkg.Files {
+               if exportsOnly {
+                       r.fileExports(f)
+               }
                r.addFile(f)
                filenames[i] = filename
                i++
@@ -397,6 +428,25 @@ func makeFuncDocs(m map[string]*ast.FuncDecl) []*FuncDoc {
        return d
 }
 
+type methodSet map[string]*FuncDoc
+
+func (mset methodSet) add(m *FuncDoc) {
+       if mset[m.Name] == nil {
+               mset[m.Name] = m
+       }
+}
+
+func (mset methodSet) sortedList() []*FuncDoc {
+       list := make([]*FuncDoc, len(mset))
+       i := 0
+       for _, m := range mset {
+               list[i] = m
+               i++
+       }
+       sort.Sort(sortFuncDoc(list))
+       return list
+}
+
 // TypeDoc is the documentation for a declared type.
 // Consts and Vars are sorted lists of constants and variables of (mostly) that type.
 // Factories is a sorted list of factory functions that return that type.
@@ -407,7 +457,9 @@ type TypeDoc struct {
        Consts    []*ValueDoc
        Vars      []*ValueDoc
        Factories []*FuncDoc
-       Methods   []*FuncDoc
+       methods   []*FuncDoc // top-level methods only
+       embedded  methodSet  // embedded methods only
+       Methods   []*FuncDoc // all methods including embedded ones
        Decl      *ast.GenDecl
        order     int
 }
@@ -429,11 +481,17 @@ func (p sortTypeDoc) Less(i, j int) bool {
 // NOTE(rsc): This would appear not to be correct for type ( )
 // blocks, but the doc extractor above has split them into
 // individual declarations.
-func (doc *docReader) makeTypeDocs(m map[string]*typeDoc) []*TypeDoc {
-       d := make([]*TypeDoc, len(m))
+func (doc *docReader) makeTypeDocs(m map[string]*typeInfo) []*TypeDoc {
+       // TODO(gri) Consider computing the embedded method information
+       //           before calling makeTypeDocs. Then this function can
+       //           be single-phased again. Also, it might simplify some
+       //           of the logic.
+       //
+       // phase 1: associate collected declarations with TypeDocs
+       list := make([]*TypeDoc, len(m))
        i := 0
        for _, old := range m {
-               // all typeDocs should have a declaration associated with
+               // all typeInfos should have a declaration associated with
                // them after processing an entire package - be conservative
                // and check
                if decl := old.decl; decl != nil {
@@ -451,10 +509,16 @@ func (doc *docReader) makeTypeDocs(m map[string]*typeDoc) []*TypeDoc {
                        t.Consts = makeValueDocs(old.values, token.CONST)
                        t.Vars = makeValueDocs(old.values, token.VAR)
                        t.Factories = makeFuncDocs(old.factories)
-                       t.Methods = makeFuncDocs(old.methods)
+                       t.methods = makeFuncDocs(old.methods)
+                       // The list of embedded types' methods is computed from the list
+                       // of embedded types, some of which may not have been processed
+                       // yet (i.e., their forward link is nil) - do this in a 2nd phase.
+                       // The final list of methods can only be computed after that -
+                       // do this in a 3rd phase.
                        t.Decl = old.decl
                        t.order = i
-                       d[i] = t
+                       old.forward = t // old has been processed
+                       list[i] = t
                        i++
                } else {
                        // no corresponding type declaration found - move any associated
@@ -477,9 +541,99 @@ func (doc *docReader) makeTypeDocs(m map[string]*typeDoc) []*TypeDoc {
                        }
                }
        }
-       d = d[0:i] // some types may have been ignored
-       sort.Sort(sortTypeDoc(d))
-       return d
+       list = list[0:i] // some types may have been ignored
+
+       // phase 2: collect embedded methods for each processed typeInfo
+       for _, old := range m {
+               if t := old.forward; t != nil {
+                       // old has been processed into t; collect embedded
+                       // methods for t from the list of processed embedded
+                       // types in old (and thus for which the methods are known)
+                       typ := t.Type
+                       if _, ok := typ.Type.(*ast.StructType); ok {
+                               // struct
+                               t.embedded = make(methodSet)
+                               collectEmbeddedMethods(t.embedded, old, typ.Name.Name)
+                       } else {
+                               // interface
+                               // TODO(gri) fix this
+                       }
+               }
+       }
+
+       // phase 3: compute final method set for each TypeDoc
+       for _, d := range list {
+               if len(d.embedded) > 0 {
+                       // there are embedded methods - exclude
+                       // the ones with names conflicting with
+                       // non-embedded methods
+                       mset := make(methodSet)
+                       // top-level methods have priority
+                       for _, m := range d.methods {
+                               mset.add(m)
+                       }
+                       // add non-conflicting embedded methods
+                       for _, m := range d.embedded {
+                               mset.add(m)
+                       }
+                       d.Methods = mset.sortedList()
+               } else {
+                       // no embedded methods
+                       d.Methods = d.methods
+               }
+       }
+
+       sort.Sort(sortTypeDoc(list))
+       return list
+}
+
+// collectEmbeddedMethods collects the embedded methods from all
+// processed embedded types found in info in mset. It considers
+// embedded types at the most shallow level first so that more
+// deeply nested embedded methods with conflicting names are
+// excluded.
+//
+func collectEmbeddedMethods(mset methodSet, info *typeInfo, recvTypeName string) {
+       for _, e := range info.embedded {
+               if e.typ.forward != nil { // == e was processed
+                       for _, m := range e.typ.forward.methods {
+                               mset.add(customizeRecv(m, e.ptr, recvTypeName))
+                       }
+                       collectEmbeddedMethods(mset, e.typ, recvTypeName)
+               }
+       }
+}
+
+func customizeRecv(m *FuncDoc, embeddedIsPtr bool, recvTypeName string) *FuncDoc {
+       if m == nil || m.Decl == nil || m.Decl.Recv == nil || len(m.Decl.Recv.List) != 1 {
+               return m // shouldn't happen, but be safe
+       }
+
+       // copy existing receiver field and set new type
+       // TODO(gri) is receiver type computation correct?
+       //           what about deeply nested embeddings?
+       newField := *m.Decl.Recv.List[0]
+       _, origRecvIsPtr := newField.Type.(*ast.StarExpr)
+       var typ ast.Expr = ast.NewIdent(recvTypeName)
+       if embeddedIsPtr || origRecvIsPtr {
+               typ = &ast.StarExpr{token.NoPos, typ}
+       }
+       newField.Type = typ
+
+       // copy existing receiver field list and set new receiver field
+       newFieldList := *m.Decl.Recv
+       newFieldList.List = []*ast.Field{&newField}
+
+       // copy existing function declaration and set new receiver field list
+       newFuncDecl := *m.Decl
+       newFuncDecl.Recv = &newFieldList
+
+       // copy existing function documentation and set new declaration
+       newM := *m
+       newM.Decl = &newFuncDecl
+       newM.Recv = typ
+
+       return &newM
 }
 
 func makeBugDocs(list []*ast.CommentGroup) []string {
@@ -523,104 +677,3 @@ func (doc *docReader) newDoc(importpath string, filenames []string) *PackageDoc
        p.Bugs = makeBugDocs(doc.bugs)
        return p
 }
-
-// ----------------------------------------------------------------------------
-// Filtering by name
-
-type Filter func(string) bool
-
-func matchFields(fields *ast.FieldList, f Filter) bool {
-       if fields != nil {
-               for _, field := range fields.List {
-                       for _, name := range field.Names {
-                               if f(name.Name) {
-                                       return true
-                               }
-                       }
-               }
-       }
-       return false
-}
-
-func matchDecl(d *ast.GenDecl, f Filter) bool {
-       for _, d := range d.Specs {
-               switch v := d.(type) {
-               case *ast.ValueSpec:
-                       for _, name := range v.Names {
-                               if f(name.Name) {
-                                       return true
-                               }
-                       }
-               case *ast.TypeSpec:
-                       if f(v.Name.Name) {
-                               return true
-                       }
-                       switch t := v.Type.(type) {
-                       case *ast.StructType:
-                               if matchFields(t.Fields, f) {
-                                       return true
-                               }
-                       case *ast.InterfaceType:
-                               if matchFields(t.Methods, f) {
-                                       return true
-                               }
-                       }
-               }
-       }
-       return false
-}
-
-func filterValueDocs(a []*ValueDoc, f Filter) []*ValueDoc {
-       w := 0
-       for _, vd := range a {
-               if matchDecl(vd.Decl, f) {
-                       a[w] = vd
-                       w++
-               }
-       }
-       return a[0:w]
-}
-
-func filterFuncDocs(a []*FuncDoc, f Filter) []*FuncDoc {
-       w := 0
-       for _, fd := range a {
-               if f(fd.Name) {
-                       a[w] = fd
-                       w++
-               }
-       }
-       return a[0:w]
-}
-
-func filterTypeDocs(a []*TypeDoc, f Filter) []*TypeDoc {
-       w := 0
-       for _, td := range a {
-               n := 0 // number of matches
-               if matchDecl(td.Decl, f) {
-                       n = 1
-               } else {
-                       // type name doesn't match, but we may have matching consts, vars, factories or methods
-                       td.Consts = filterValueDocs(td.Consts, f)
-                       td.Vars = filterValueDocs(td.Vars, f)
-                       td.Factories = filterFuncDocs(td.Factories, f)
-                       td.Methods = filterFuncDocs(td.Methods, f)
-                       n += len(td.Consts) + len(td.Vars) + len(td.Factories) + len(td.Methods)
-               }
-               if n > 0 {
-                       a[w] = td
-                       w++
-               }
-       }
-       return a[0:w]
-}
-
-// Filter eliminates documentation for names that don't pass through the filter f.
-// TODO: Recognize "Type.Method" as a name.
-//
-func (p *PackageDoc) Filter(f Filter) {
-       p.Consts = filterValueDocs(p.Consts, f)
-       p.Vars = filterValueDocs(p.Vars, f)
-       p.Types = filterTypeDocs(p.Types, f)
-       p.Funcs = filterFuncDocs(p.Funcs, f)
-       p.Doc = "" // don't show top-level package doc
-}
diff --git a/libgo/go/go/doc/exports.go b/libgo/go/go/doc/exports.go
new file mode 100644 (file)
index 0000000..9cd186a
--- /dev/null
@@ -0,0 +1,167 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements export filtering of an AST.
+
+package doc
+
+import "go/ast"
+
+func filterIdentList(list []*ast.Ident) []*ast.Ident {
+       j := 0
+       for _, x := range list {
+               if ast.IsExported(x.Name) {
+                       list[j] = x
+                       j++
+               }
+       }
+       return list[0:j]
+}
+
+func baseName(x ast.Expr) *ast.Ident {
+       switch t := x.(type) {
+       case *ast.Ident:
+               return t
+       case *ast.SelectorExpr:
+               if _, ok := t.X.(*ast.Ident); ok {
+                       return t.Sel
+               }
+       case *ast.StarExpr:
+               return baseName(t.X)
+       }
+       return nil
+}
+
+func (doc *docReader) filterFieldList(fields *ast.FieldList) (removedFields bool) {
+       if fields == nil {
+               return false
+       }
+       list := fields.List
+       j := 0
+       for _, f := range list {
+               keepField := false
+               if len(f.Names) == 0 {
+                       // anonymous field
+                       name := baseName(f.Type)
+                       keepField = name != nil && name.IsExported()
+               } else {
+                       n := len(f.Names)
+                       f.Names = filterIdentList(f.Names)
+                       if len(f.Names) < n {
+                               removedFields = true
+                       }
+                       keepField = len(f.Names) > 0
+               }
+               if keepField {
+                       doc.filterType(f.Type)
+                       list[j] = f
+                       j++
+               }
+       }
+       if j < len(list) {
+               removedFields = true
+       }
+       fields.List = list[0:j]
+       return
+}
+
+func (doc *docReader) filterParamList(fields *ast.FieldList) bool {
+       if fields == nil {
+               return false
+       }
+       var b bool
+       for _, f := range fields.List {
+               if doc.filterType(f.Type) {
+                       b = true
+               }
+       }
+       return b
+}
+
+func (doc *docReader) filterType(typ ast.Expr) bool {
+       switch t := typ.(type) {
+       case *ast.Ident:
+               return ast.IsExported(t.Name)
+       case *ast.ParenExpr:
+               return doc.filterType(t.X)
+       case *ast.ArrayType:
+               return doc.filterType(t.Elt)
+       case *ast.StructType:
+               if doc.filterFieldList(t.Fields) {
+                       t.Incomplete = true
+               }
+               return len(t.Fields.List) > 0
+       case *ast.FuncType:
+               b1 := doc.filterParamList(t.Params)
+               b2 := doc.filterParamList(t.Results)
+               return b1 || b2
+       case *ast.InterfaceType:
+               if doc.filterFieldList(t.Methods) {
+                       t.Incomplete = true
+               }
+               return len(t.Methods.List) > 0
+       case *ast.MapType:
+               b1 := doc.filterType(t.Key)
+               b2 := doc.filterType(t.Value)
+               return b1 || b2
+       case *ast.ChanType:
+               return doc.filterType(t.Value)
+       }
+       return false
+}
+
+func (doc *docReader) filterSpec(spec ast.Spec) bool {
+       switch s := spec.(type) {
+       case *ast.ValueSpec:
+               s.Names = filterIdentList(s.Names)
+               if len(s.Names) > 0 {
+                       doc.filterType(s.Type)
+                       return true
+               }
+       case *ast.TypeSpec:
+               if ast.IsExported(s.Name.Name) {
+                       doc.filterType(s.Type)
+                       return true
+               }
+       }
+       return false
+}
+
+func (doc *docReader) filterSpecList(list []ast.Spec) []ast.Spec {
+       j := 0
+       for _, s := range list {
+               if doc.filterSpec(s) {
+                       list[j] = s
+                       j++
+               }
+       }
+       return list[0:j]
+}
+
+func (doc *docReader) filterDecl(decl ast.Decl) bool {
+       switch d := decl.(type) {
+       case *ast.GenDecl:
+               d.Specs = doc.filterSpecList(d.Specs)
+               return len(d.Specs) > 0
+       case *ast.FuncDecl:
+               return ast.IsExported(d.Name.Name)
+       }
+       return false
+}
+
+// fileExports trims the AST for a Go file in place such that
+// only exported nodes remain. fileExports returns true if
+// there are exported declarations; otherwise it returns false.
+//
+func (doc *docReader) fileExports(src *ast.File) bool {
+       j := 0
+       for _, d := range src.Decls {
+               if doc.filterDecl(d) {
+                       src.Decls[j] = d
+                       j++
+               }
+       }
+       src.Decls = src.Decls[0:j]
+       return j > 0
+}
diff --git a/libgo/go/go/doc/filter.go b/libgo/go/go/doc/filter.go
new file mode 100644 (file)
index 0000000..71c2ebb
--- /dev/null
@@ -0,0 +1,105 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package doc
+
+import "go/ast"
+
+type Filter func(string) bool
+
+func matchFields(fields *ast.FieldList, f Filter) bool {
+       if fields != nil {
+               for _, field := range fields.List {
+                       for _, name := range field.Names {
+                               if f(name.Name) {
+                                       return true
+                               }
+                       }
+               }
+       }
+       return false
+}
+
+func matchDecl(d *ast.GenDecl, f Filter) bool {
+       for _, d := range d.Specs {
+               switch v := d.(type) {
+               case *ast.ValueSpec:
+                       for _, name := range v.Names {
+                               if f(name.Name) {
+                                       return true
+                               }
+                       }
+               case *ast.TypeSpec:
+                       if f(v.Name.Name) {
+                               return true
+                       }
+                       switch t := v.Type.(type) {
+                       case *ast.StructType:
+                               if matchFields(t.Fields, f) {
+                                       return true
+                               }
+                       case *ast.InterfaceType:
+                               if matchFields(t.Methods, f) {
+                                       return true
+                               }
+                       }
+               }
+       }
+       return false
+}
+
+func filterValueDocs(a []*ValueDoc, f Filter) []*ValueDoc {
+       w := 0
+       for _, vd := range a {
+               if matchDecl(vd.Decl, f) {
+                       a[w] = vd
+                       w++
+               }
+       }
+       return a[0:w]
+}
+
+func filterFuncDocs(a []*FuncDoc, f Filter) []*FuncDoc {
+       w := 0
+       for _, fd := range a {
+               if f(fd.Name) {
+                       a[w] = fd
+                       w++
+               }
+       }
+       return a[0:w]
+}
+
+func filterTypeDocs(a []*TypeDoc, f Filter) []*TypeDoc {
+       w := 0
+       for _, td := range a {
+               n := 0 // number of matches
+               if matchDecl(td.Decl, f) {
+                       n = 1
+               } else {
+                       // type name doesn't match, but we may have matching consts, vars, factories or methods
+                       td.Consts = filterValueDocs(td.Consts, f)
+                       td.Vars = filterValueDocs(td.Vars, f)
+                       td.Factories = filterFuncDocs(td.Factories, f)
+                       td.Methods = filterFuncDocs(td.Methods, f)
+                       n += len(td.Consts) + len(td.Vars) + len(td.Factories) + len(td.Methods)
+               }
+               if n > 0 {
+                       a[w] = td
+                       w++
+               }
+       }
+       return a[0:w]
+}
+
+// Filter eliminates documentation for names that don't pass through the filter f.
+// TODO: Recognize "Type.Method" as a name.
+//
+func (p *PackageDoc) Filter(f Filter) {
+       p.Consts = filterValueDocs(p.Consts, f)
+       p.Vars = filterValueDocs(p.Vars, f)
+       p.Types = filterTypeDocs(p.Types, f)
+       p.Funcs = filterFuncDocs(p.Funcs, f)
+       p.Doc = "" // don't show top-level package doc
+}
index f0a8055f4c1227cf211969395e5a890b35ba92b1..9fbed2d2ca35de31d605caf2336722ce22225d80 100644 (file)
@@ -144,28 +144,31 @@ func (p *parser) declare(decl, data interface{}, scope *ast.Scope, kind ast.ObjK
        }
 }
 
-func (p *parser) shortVarDecl(idents []*ast.Ident) {
+func (p *parser) shortVarDecl(decl *ast.AssignStmt, list []ast.Expr) {
        // Go spec: A short variable declaration may redeclare variables
        // provided they were originally declared in the same block with
        // the same type, and at least one of the non-blank variables is new.
        n := 0 // number of new variables
-       for _, ident := range idents {
-               assert(ident.Obj == nil, "identifier already declared or resolved")
-               obj := ast.NewObj(ast.Var, ident.Name)
-               // short var declarations cannot have redeclaration errors
-               // and are not global => no need to remember the respective
-               // declaration
-               ident.Obj = obj
-               if ident.Name != "_" {
-                       if alt := p.topScope.Insert(obj); alt != nil {
-                               ident.Obj = alt // redeclaration
-                       } else {
-                               n++ // new declaration
+       for _, x := range list {
+               if ident, isIdent := x.(*ast.Ident); isIdent {
+                       assert(ident.Obj == nil, "identifier already declared or resolved")
+                       obj := ast.NewObj(ast.Var, ident.Name)
+                       // remember corresponding assignment for other tools
+                       obj.Decl = decl
+                       ident.Obj = obj
+                       if ident.Name != "_" {
+                               if alt := p.topScope.Insert(obj); alt != nil {
+                                       ident.Obj = alt // redeclaration
+                               } else {
+                                       n++ // new declaration
+                               }
                        }
+               } else {
+                       p.errorExpected(x.Pos(), "identifier")
                }
        }
        if n == 0 && p.mode&DeclarationErrors != 0 {
-               p.error(idents[0].Pos(), "no new variables on left side of :=")
+               p.error(list[0].Pos(), "no new variables on left side of :=")
        }
 }
 
@@ -522,7 +525,7 @@ func (p *parser) makeIdentList(list []ast.Expr) []*ast.Ident {
        for i, x := range list {
                ident, isIdent := x.(*ast.Ident)
                if !isIdent {
-                       pos := x.(ast.Expr).Pos()
+                       pos := x.Pos()
                        p.errorExpected(pos, "identifier")
                        ident = &ast.Ident{pos, "_", nil}
                }
@@ -1400,10 +1403,11 @@ func (p *parser) parseSimpleStmt(mode int) (ast.Stmt, bool) {
                } else {
                        y = p.parseRhsList()
                }
+               as := &ast.AssignStmt{x, pos, tok, y}
                if tok == token.DEFINE {
-                       p.shortVarDecl(p.makeIdentList(x))
+                       p.shortVarDecl(as, x)
                }
-               return &ast.AssignStmt{x, pos, tok, y}, isRange
+               return as, isRange
        }
 
        if len(x) > 1 {
@@ -1715,34 +1719,28 @@ func (p *parser) parseCommClause() *ast.CommClause {
                        comm = &ast.SendStmt{lhs[0], arrow, rhs}
                } else {
                        // RecvStmt
-                       pos := p.pos
-                       tok := p.tok
-                       var rhs ast.Expr
-                       if tok == token.ASSIGN || tok == token.DEFINE {
+                       if tok := p.tok; tok == token.ASSIGN || tok == token.DEFINE {
                                // RecvStmt with assignment
                                if len(lhs) > 2 {
                                        p.errorExpected(lhs[0].Pos(), "1 or 2 expressions")
                                        // continue with first two expressions
                                        lhs = lhs[0:2]
                                }
+                               pos := p.pos
                                p.next()
-                               rhs = p.parseRhs()
-                               if tok == token.DEFINE && lhs != nil {
-                                       p.shortVarDecl(p.makeIdentList(lhs))
+                               rhs := p.parseRhs()
+                               as := &ast.AssignStmt{lhs, pos, tok, []ast.Expr{rhs}}
+                               if tok == token.DEFINE {
+                                       p.shortVarDecl(as, lhs)
                                }
+                               comm = as
                        } else {
-                               // rhs must be single receive operation
+                               // lhs must be single receive operation
                                if len(lhs) > 1 {
                                        p.errorExpected(lhs[0].Pos(), "1 expression")
                                        // continue with first expression
                                }
-                               rhs = lhs[0]
-                               lhs = nil // there is no lhs
-                       }
-                       if lhs != nil {
-                               comm = &ast.AssignStmt{lhs, pos, tok, []ast.Expr{rhs}}
-                       } else {
-                               comm = &ast.ExprStmt{rhs}
+                               comm = &ast.ExprStmt{lhs[0]}
                        }
                }
        } else {
index b2a48c28a733bbe4d4431927055398b7f320ce37..6817cc42addef4323dd9dd22dd9083b52ef35eac 100644 (file)
@@ -39,7 +39,10 @@ import (
 //            future (not yet interspersed) comments in this function.
 //
 func (p *printer) linebreak(line, min int, ws whiteSpace, newSection bool) (printedBreak bool) {
-       n := p.nlines(line-p.pos.Line, min)
+       n := nlimit(line - p.pos.Line)
+       if n < min {
+               n = min
+       }
        if n > 0 {
                p.print(ws)
                if newSection {
@@ -361,9 +364,10 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
        lbrace := fields.Opening
        list := fields.List
        rbrace := fields.Closing
+       hasComments := isIncomplete || p.commentBefore(p.fset.Position(rbrace))
        srcIsOneLine := lbrace.IsValid() && rbrace.IsValid() && p.fset.Position(lbrace).Line == p.fset.Position(rbrace).Line
 
-       if !isIncomplete && !p.commentBefore(p.fset.Position(rbrace)) && srcIsOneLine {
+       if !hasComments && srcIsOneLine {
                // possibly a one-line struct/interface
                if len(list) == 0 {
                        // no blank between keyword and {} in this case
@@ -388,9 +392,13 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool)
                        return
                }
        }
+       // hasComments || !srcIsOneLine
+
+       p.print(blank, lbrace, token.LBRACE, indent)
+       if hasComments || len(list) > 0 {
+               p.print(formfeed)
+       }
 
-       // at least one entry or incomplete
-       p.print(blank, lbrace, token.LBRACE, indent, formfeed)
        if isStruct {
 
                sep := vtab
@@ -1509,9 +1517,14 @@ func (p *printer) file(src *ast.File) {
                        prev := tok
                        tok = declToken(d)
                        // if the declaration token changed (e.g., from CONST to TYPE)
+                       // or the next declaration has documentation associated with it,
                        // print an empty line between top-level declarations
+                       // (because p.linebreak is called with the position of d, which
+                       // is past any documentation, the minimum requirement is satisfied
+                       // even w/o the extra getDoc(d) nil-check - leave it in case the
+                       // linebreak logic improves - there's already a TODO).
                        min := 1
-                       if prev != tok {
+                       if prev != tok || getDoc(d) != nil {
                                min = 2
                        }
                        p.linebreak(p.fset.Position(d.Pos()).Line, min, ignore, false)
index 8538236c2c953f75d60c58156d603b78c82bc424..a78cfc65fccb372399048449b35c282900599d13 100644 (file)
@@ -18,8 +18,11 @@ import (
        "text/tabwriter"
 )
 
-const debug = false // enable for debugging
-const infinity = 1 << 30
+const (
+       maxNewlines = 2     // max. number of newlines between source text
+       debug       = false // enable for debugging
+       infinity    = 1 << 30
+)
 
 type whiteSpace byte
 
@@ -89,21 +92,7 @@ func (p *printer) internalError(msg ...interface{}) {
        }
 }
 
-// nlines returns the adjusted number of linebreaks given the desired number
-// of breaks n such that min <= result <= max.
-//
-func (p *printer) nlines(n, min int) int {
-       const max = 2 // max. number of newlines
-       switch {
-       case n < min:
-               return min
-       case n > max:
-               return max
-       }
-       return n
-}
-
-// writeByte writes a single byte to p.output and updates p.pos.
+// writeByte writes ch to p.output and updates p.pos.
 func (p *printer) writeByte(ch byte) {
        p.output.WriteByte(ch)
        p.pos.Offset++
@@ -128,13 +117,11 @@ func (p *printer) writeByte(ch byte) {
        }
 }
 
-// writeNewlines writes up to n newlines to p.output and updates p.pos.
-// The actual number of newlines written is limited by nlines.
-// nl must be one of '\n' or '\f'.
-//
-func (p *printer) writeNewlines(n int, nl byte) {
-       for n = p.nlines(n, 0); n > 0; n-- {
-               p.writeByte(nl)
+// writeByteN writes ch n times to p.output and updates p.pos.
+func (p *printer) writeByteN(ch byte, n int) {
+       for n > 0 {
+               p.writeByte(ch)
+               n--
        }
 }
 
@@ -223,8 +210,8 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, prev, comment *as
        }
 
        if pos.IsValid() && pos.Filename != p.last.Filename {
-               // comment in a different file - separate with newlines (writeNewlines will limit the number)
-               p.writeNewlines(10, '\f')
+               // comment in a different file - separate with newlines
+               p.writeByteN('\f', maxNewlines)
                return
        }
 
@@ -270,6 +257,7 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, prev, comment *as
        } else {
                // comment on a different line:
                // separate with at least one line break
+               droppedLinebreak := false
                if prev == nil {
                        // first comment of a comment group
                        j := 0
@@ -295,6 +283,7 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, prev, comment *as
                                case newline, formfeed:
                                        // TODO(gri): may want to keep formfeed info in some cases
                                        p.wsbuf[i] = ignore
+                                       droppedLinebreak = true
                                }
                                j = i
                                break
@@ -302,25 +291,41 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, prev, comment *as
                        p.writeWhitespace(j)
                }
 
-               // turn off indent if we're about to print a line directive.
-               indent := p.indent
-               if strings.HasPrefix(comment.Text, linePrefix) {
-                       p.indent = 0
+               // determine number of linebreaks before the comment
+               n := 0
+               if pos.IsValid() && p.last.IsValid() {
+                       n = pos.Line - p.last.Line
+                       if n < 0 { // should never happen
+                               n = 0
+                       }
+               }
+
+               // at the package scope level only (p.indent == 0),
+               // add an extra newline if we dropped one before:
+               // this preserves a blank line before documentation
+               // comments at the package scope level (issue 2570)
+               if p.indent == 0 && droppedLinebreak {
+                       n++
                }
 
-               // use formfeeds to break columns before a comment;
-               // this is analogous to using formfeeds to separate
-               // individual lines of /*-style comments - but make
-               // sure there is at least one line break if the previous
-               // comment was a line comment
-               n := pos.Line - p.last.Line // if !pos.IsValid(), pos.Line == 0, and n will be 0
-               if n <= 0 && prev != nil && prev.Text[1] == '/' {
+               // make sure there is at least one line break
+               // if the previous comment was a line comment
+               if n == 0 && prev != nil && prev.Text[1] == '/' {
                        n = 1
                }
+
                if n > 0 {
-                       p.writeNewlines(n, '\f')
+                       // turn off indent if we're about to print a line directive
+                       indent := p.indent
+                       if strings.HasPrefix(comment.Text, linePrefix) {
+                               p.indent = 0
+                       }
+                       // use formfeeds to break columns before a comment;
+                       // this is analogous to using formfeeds to separate
+                       // individual lines of /*-style comments
+                       p.writeByteN('\f', nlimit(n))
+                       p.indent = indent // restore indent
                }
-               p.indent = indent
        }
 }
 
@@ -550,10 +555,11 @@ func (p *printer) writeComment(comment *ast.Comment) {
 // writeCommentSuffix writes a line break after a comment if indicated
 // and processes any leftover indentation information. If a line break
 // is needed, the kind of break (newline vs formfeed) depends on the
-// pending whitespace. writeCommentSuffix returns true if a pending
-// formfeed was dropped from the whitespace buffer.
+// pending whitespace. The writeCommentSuffix result indicates if a
+// newline was written or if a formfeed was dropped from the whitespace
+// buffer.
 //
-func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) {
+func (p *printer) writeCommentSuffix(needsLinebreak bool) (wroteNewline, droppedFF bool) {
        for i, ch := range p.wsbuf {
                switch ch {
                case blank, vtab:
@@ -566,6 +572,7 @@ func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) {
                        // but remember if we dropped any formfeeds
                        if needsLinebreak {
                                needsLinebreak = false
+                               wroteNewline = true
                        } else {
                                if ch == formfeed {
                                        droppedFF = true
@@ -579,6 +586,7 @@ func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) {
        // make sure we have a line break
        if needsLinebreak {
                p.writeByte('\n')
+               wroteNewline = true
        }
 
        return
@@ -587,10 +595,10 @@ func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) {
 // intersperseComments consumes all comments that appear before the next token
 // tok and prints it together with the buffered whitespace (i.e., the whitespace
 // that needs to be written before the next token). A heuristic is used to mix
-// the comments and whitespace. intersperseComments returns true if a pending
-// formfeed was dropped from the whitespace buffer.
+// the comments and whitespace. The intersperseComments result indicates if a
+// newline was written or if a formfeed was dropped from the whitespace buffer.
 //
-func (p *printer) intersperseComments(next token.Position, tok token.Token) (droppedFF bool) {
+func (p *printer) intersperseComments(next token.Position, tok token.Token) (wroteNewline, droppedFF bool) {
        var last *ast.Comment
        for ; p.commentBefore(next); p.cindex++ {
                for _, c := range p.comments[p.cindex].List {
@@ -618,7 +626,7 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (dro
        // no comment was written - we should never reach here since
        // intersperseComments should not be called in that case
        p.internalError("intersperseComments called without pending comments")
-       return false
+       return
 }
 
 // whiteWhitespace writes the first n whitespace entries.
@@ -671,6 +679,14 @@ func (p *printer) writeWhitespace(n int) {
 // ----------------------------------------------------------------------------
 // Printing interface
 
+// nlines limits n to maxNewlines.
+func nlimit(n int) int {
+       if n > maxNewlines {
+               n = maxNewlines
+       }
+       return n
+}
+
 func mayCombine(prev token.Token, next byte) (b bool) {
        switch prev {
        case token.INT:
@@ -765,17 +781,22 @@ func (p *printer) print(args ...interface{}) {
                p.pos = next
 
                if data != "" {
-                       nl := byte('\n')
-                       if p.flush(next, tok) {
-                               nl = '\f' // dropped formfeed before
-                       }
+                       wroteNewline, droppedFF := p.flush(next, tok)
 
                        // intersperse extra newlines if present in the source
                        // (don't do this in flush as it will cause extra newlines
-                       // at the end of a file) - use formfeeds if we dropped one
-                       // before
-                       if n := next.Line - p.pos.Line; n > 0 {
-                               p.writeNewlines(n, nl)
+                       // at the end of a file)
+                       n := nlimit(next.Line - p.pos.Line)
+                       // don't exceed maxNewlines if we already wrote one
+                       if wroteNewline && n == maxNewlines {
+                               n = maxNewlines - 1
+                       }
+                       if n > 0 {
+                               ch := byte('\n')
+                               if droppedFF {
+                                       ch = '\f' // use formfeed since we dropped one before
+                               }
+                               p.writeByteN(ch, n)
                        }
 
                        p.writeItem(next, data, isLit)
@@ -790,16 +811,15 @@ func (p *printer) commentBefore(next token.Position) bool {
        return p.cindex < len(p.comments) && p.fset.Position(p.comments[p.cindex].List[0].Pos()).Offset < next.Offset
 }
 
-// Flush prints any pending comments and whitespace occurring
-// textually before the position of the next token tok. Flush
-// returns true if a pending formfeed character was dropped
-// from the whitespace buffer as a result of interspersing
-// comments.
+// Flush prints any pending comments and whitespace occurring textually
+// before the position of the next token tok. The Flush result indicates
+// if a newline was written or if a formfeed was dropped from the whitespace
+// buffer.
 //
-func (p *printer) flush(next token.Position, tok token.Token) (droppedFF bool) {
+func (p *printer) flush(next token.Position, tok token.Token) (wroteNewline, droppedFF bool) {
        if p.commentBefore(next) {
                // if there are comments before the next item, intersperse them
-               droppedFF = p.intersperseComments(next, tok)
+               wroteNewline, droppedFF = p.intersperseComments(next, tok)
        } else {
                // otherwise, write any leftover whitespace
                p.writeWhitespace(len(p.wsbuf))
@@ -810,7 +830,8 @@ func (p *printer) flush(next token.Position, tok token.Token) (droppedFF bool) {
 // getNode returns the ast.CommentGroup associated with n, if any.
 func getDoc(n ast.Node) *ast.CommentGroup {
        switch n := n.(type) {
-       // *ast.Fields cannot be printed separately - ignore for now
+       case *ast.Field:
+               return n.Doc
        case *ast.ImportSpec:
                return n.Doc
        case *ast.ValueSpec:
index 7b332252c4ec0ad26ca17930c92d6fc0f5ab19f3..d2ad9e3a2ff94dc4e7747ade0df954dafa2cfe81 100644 (file)
@@ -106,7 +106,7 @@ type S3 struct {
 var x int      // x
 var ()
 
-// This comment SHOULD be associated with the next declaration.
+// This comment SHOULD be associated with f0.
 func f0() {
        const pi = 3.14 // pi
        var s1 struct{} /* an empty struct */   /* foo */
@@ -115,8 +115,9 @@ func f0() {
        var s2 struct{} = struct{}{}
        x := pi
 }
+
 //
-// NO SPACE HERE
+// This comment should be associated with f1, with one blank line before the comment.
 //
 func f1() {
        f0()
index 2a9a86b681584c2748ea58fcf97a9dc4dbf859a1..222e0a713d4621786ab449c0ecfc6084d6d84a1f 100644 (file)
@@ -107,7 +107,7 @@ var x int  // x
 var ()
 
 
-// This comment SHOULD be associated with the next declaration.
+// This comment SHOULD be associated with f0.
 func f0() {
        const pi = 3.14  // pi
        var s1 struct {}  /* an empty struct */ /* foo */
@@ -117,7 +117,7 @@ func f0() {
        x := pi
 }
 //
-// NO SPACE HERE
+// This comment should be associated with f1, with one blank line before the comment.
 //
 func f1() {
        f0()
@@ -130,7 +130,7 @@ func f1() {
 
 
 func _() {
-       // this comment should be properly indented
+// this comment should be properly indented
 }
 
 
index bfa2568c21fd29ea3f8ea5697f4591be112d01f0..239ba890304599a0305f5567c666f3c518461fde 100644 (file)
@@ -115,6 +115,18 @@ import _ "io"
 
 var _ int
 
+// at least one empty line between declarations of the same kind
+// if there is associated documentation (was issue 2570)
+type T1 struct{}
+
+// T2 comment
+type T2 struct {
+}      // should be a two-line struct
+
+// T3 comment
+type T2 struct {
+}      // should be a two-line struct
+
 // printing of constant literals
 const (
        _       = "foobar"
@@ -286,6 +298,15 @@ type _ struct {
        }
 }
 
+// no blank lines in empty structs and interfaces, but leave 1- or 2-line layout alone
+type _ struct{}
+type _ struct {
+}
+
+type _ interface{}
+type _ interface {
+}
+
 // no tabs for single or ungrouped decls
 func _() {
        const xxxxxx = 0
index 1d69c57b517466994fde21dc225b58261239147b..68f90308a362b942fb55a72ffe682346d5caeddf 100644 (file)
@@ -115,6 +115,20 @@ import (
 import _ "io"
 var _ int
 
+// at least one empty line between declarations of the same kind
+// if there is associated documentation (was issue 2570)
+type T1 struct{}
+// T2 comment
+type T2 struct {
+} // should be a two-line struct
+
+
+// T3 comment
+type T2 struct {
+
+
+} // should be a two-line struct
+
 
 // printing of constant literals
 const (
@@ -293,6 +307,18 @@ type _ struct {
 }
 
 
+// no blank lines in empty structs and interfaces, but leave 1- or 2-line layout alone
+type _ struct{            }
+type _ struct {
+
+}
+
+type _ interface{            }
+type _ interface {
+
+}
+
+
 // no tabs for single or ungrouped decls
 func _() {
        const xxxxxx = 0
index a6d85107f0b307b154d005f591c4f55d495ceaed..90e1743557d382007e8fcfe664e3edd157886f48 100644 (file)
@@ -271,7 +271,6 @@ func _() {
        // Known bug: The first use call may have more than one empty line before
        //            (see go/printer/nodes.go, func linebreak).
 
-
        use(x)
 
        if x < x {
@@ -386,7 +385,6 @@ L:  // A comment on the same line as the label, followed by a single empty line.
        // Known bug: There may be more than one empty line before MoreCode()
        //            (see go/printer/nodes.go, func linebreak).
 
-
        MoreCode()
 }
 
index cef9c4865083fd333f1a9a888b240695a841b803..7fb0104e450a51d74df116cd347a137e0ccdbbb1 100644 (file)
@@ -426,13 +426,16 @@ func (S *Scanner) scanString() {
        S.next()
 }
 
-func (S *Scanner) scanRawString() {
+func (S *Scanner) scanRawString() (hasCR bool) {
        // '`' opening already consumed
        offs := S.offset - 1
 
        for S.ch != '`' {
                ch := S.ch
                S.next()
+               if ch == '\r' {
+                       hasCR = true
+               }
                if ch < 0 {
                        S.error(offs, "string not terminated")
                        break
@@ -440,6 +443,7 @@ func (S *Scanner) scanRawString() {
        }
 
        S.next()
+       return
 }
 
 func (S *Scanner) skipWhitespace() {
@@ -490,6 +494,18 @@ func (S *Scanner) switch4(tok0, tok1 token.Token, ch2 rune, tok2, tok3 token.Tok
        return tok0
 }
 
+func stripCR(b []byte) []byte {
+       c := make([]byte, len(b))
+       i := 0
+       for _, ch := range b {
+               if ch != '\r' {
+                       c[i] = ch
+                       i++
+               }
+       }
+       return c[:i]
+}
+
 // Scan scans the next token and returns the token position,
 // the token, and the literal string corresponding to the
 // token. The source end is indicated by token.EOF.
@@ -518,6 +534,7 @@ scanAgain:
        insertSemi := false
        offs := S.offset
        tok := token.ILLEGAL
+       hasCR := false
 
        // determine token value
        switch ch := S.ch; {
@@ -556,7 +573,7 @@ scanAgain:
                case '`':
                        insertSemi = true
                        tok = token.STRING
-                       S.scanRawString()
+                       hasCR = S.scanRawString()
                case ':':
                        tok = S.switch2(token.COLON, token.DEFINE)
                case '.':
@@ -663,5 +680,9 @@ scanAgain:
        // TODO(gri): The scanner API should change such that the literal string
        //            is only valid if an actual literal was scanned. This will
        //            permit a more efficient implementation.
-       return S.file.Pos(offs), tok, string(S.src[offs:S.offset])
+       lit := S.src[offs:S.offset]
+       if hasCR {
+               lit = stripCR(lit)
+       }
+       return S.file.Pos(offs), tok, string(lit)
 }
index 7ed927a49fa976e605ee600d8877397186f4881b..dc8ab2a748a08a7826ccef1dd103ea1110a13779 100644 (file)
@@ -83,6 +83,8 @@ var tokens = [...]elt{
                "`",
                literal,
        },
+       {token.STRING, "`\r`", literal},
+       {token.STRING, "`foo\r\nbar`", literal},
 
        // Operators and delimiters
        {token.ADD, "+", operator},
@@ -239,8 +241,16 @@ func TestScan(t *testing.T) {
                if tok != e.tok {
                        t.Errorf("bad token for %q: got %s, expected %s", lit, tok, e.tok)
                }
-               if e.tok.IsLiteral() && lit != e.lit {
-                       t.Errorf("bad literal for %q: got %q, expected %q", lit, lit, e.lit)
+               if e.tok.IsLiteral() {
+                       // no CRs in raw string literals
+                       elit := e.lit
+                       if elit[0] == '`' {
+                               elit = string(stripCR([]byte(elit)))
+                               epos.Offset += len(e.lit) - len(lit) // correct position
+                       }
+                       if lit != elit {
+                               t.Errorf("bad literal for %q: got %q, expected %q", lit, lit, elit)
+                       }
                }
                if tokenclass(tok) != e.class {
                        t.Errorf("bad class for %q: got %d, expected %d", lit, tokenclass(tok), e.class)
index 832e9dbc096677bf0e40b2562fcfbe1c41920dde..d7cc8bb9a9931f33a925b98c3a2930ddf112bf82 100644 (file)
@@ -7,7 +7,7 @@ package html
 // Section 12.2.3.2 of the HTML5 specification says "The following elements
 // have varying levels of special parsing rules".
 // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#the-stack-of-open-elements
-var isSpecialElement = map[string]bool{
+var isSpecialElementMap = map[string]bool{
        "address":    true,
        "applet":     true,
        "area":       true,
@@ -88,3 +88,13 @@ var isSpecialElement = map[string]bool{
        "wbr":        true,
        "xmp":        true,
 }
+
+func isSpecialElement(element *Node) bool {
+       switch element.Namespace {
+       case "", "html":
+               return isSpecialElementMap[element.Data]
+       case "svg":
+               return element.Data == "foreignObject"
+       }
+       return false
+}
index 4cb246969e54ca1c3b860b167d718bfd0376c4be..6962e643932cae1a27a559697393ca33400de8fb 100644 (file)
@@ -319,10 +319,7 @@ func (p *parser) resetInsertionMode() {
                case "html":
                        p.im = beforeHeadIM
                default:
-                       if p.top().Namespace == "" {
-                               continue
-                       }
-                       p.im = inForeignContentIM
+                       continue
                }
                return
        }
@@ -705,7 +702,7 @@ func inBodyIM(p *parser) bool {
                                case "address", "div", "p":
                                        continue
                                default:
-                                       if !isSpecialElement[node.Data] {
+                                       if !isSpecialElement(node) {
                                                continue
                                        }
                                }
@@ -723,7 +720,7 @@ func inBodyIM(p *parser) bool {
                                case "address", "div", "p":
                                        continue
                                default:
-                                       if !isSpecialElement[node.Data] {
+                                       if !isSpecialElement(node) {
                                                continue
                                        }
                                }
@@ -814,7 +811,6 @@ func inBodyIM(p *parser) bool {
                        // TODO: adjust foreign attributes.
                        p.addElement(p.tok.Data, p.tok.Attr)
                        p.top().Namespace = namespace
-                       p.im = inForeignContentIM
                        return true
                case "caption", "col", "colgroup", "frame", "head", "tbody", "td", "tfoot", "th", "thead", "tr":
                        // Ignore the token.
@@ -895,7 +891,7 @@ func (p *parser) inBodyEndTagFormatting(tag string) {
                // Steps 5-6. Find the furthest block.
                var furthestBlock *Node
                for _, e := range p.oe[feIndex:] {
-                       if isSpecialElement[e.Data] {
+                       if isSpecialElement(e) {
                                furthestBlock = e
                                break
                        }
@@ -988,7 +984,7 @@ func (p *parser) inBodyEndTagOther(tag string) {
                        p.oe = p.oe[:i]
                        break
                }
-               if isSpecialElement[p.oe[i].Data] {
+               if isSpecialElement(p.oe[i]) {
                        break
                }
        }
@@ -1206,6 +1202,13 @@ func inTableBodyIM(p *parser) bool {
                        add = true
                        data = "tr"
                        consumed = false
+               case "caption", "col", "colgroup", "tbody", "tfoot", "thead":
+                       if !p.popUntil(tableScopeStopTags, "tbody", "thead", "tfoot") {
+                               // Ignore the token.
+                               return true
+                       }
+                       p.im = inTableIM
+                       return false
                default:
                        // TODO.
                }
@@ -1569,6 +1572,19 @@ func afterAfterFramesetIM(p *parser) bool {
                        Type: CommentNode,
                        Data: p.tok.Data,
                })
+       case TextToken:
+               // Ignore all text but whitespace.
+               s := strings.Map(func(c rune) rune {
+                       switch c {
+                       case ' ', '\t', '\n', '\f', '\r':
+                               return c
+                       }
+                       return -1
+               }, p.tok.Data)
+               if s != "" {
+                       p.reconstructActiveFormattingElements()
+                       p.addText(s)
+               }
        case StartTagToken:
                switch p.tok.Data {
                case "html":
@@ -1583,8 +1599,19 @@ func afterAfterFramesetIM(p *parser) bool {
 }
 
 // Section 12.2.5.5.
-func inForeignContentIM(p *parser) bool {
+func parseForeignContent(p *parser) bool {
        switch p.tok.Type {
+       case TextToken:
+               // TODO: HTML integration points.
+               if p.top().Namespace == "" {
+                       inBodyIM(p)
+                       p.resetInsertionMode()
+                       return true
+               }
+               if p.framesetOK {
+                       p.framesetOK = strings.TrimLeft(p.tok.Data, whitespace) == ""
+               }
+               p.addText(p.tok.Data)
        case CommentToken:
                p.addChild(&Node{
                        Type: CommentNode,
@@ -1592,7 +1619,14 @@ func inForeignContentIM(p *parser) bool {
                })
        case StartTagToken:
                if breakout[p.tok.Data] {
-                       // TODO.
+                       for i := len(p.oe) - 1; i >= 0; i-- {
+                               // TODO: HTML, MathML integration points.
+                               if p.oe[i].Namespace == "" {
+                                       p.oe = p.oe[:i+1]
+                                       break
+                               }
+                       }
+                       return false
                }
                switch p.top().Namespace {
                case "mathml":
@@ -1606,13 +1640,36 @@ func inForeignContentIM(p *parser) bool {
                // TODO: adjust foreign attributes.
                p.addElement(p.tok.Data, p.tok.Attr)
        case EndTagToken:
-               // TODO.
+               for i := len(p.oe) - 1; i >= 0; i-- {
+                       if p.oe[i].Namespace == "" {
+                               return p.im(p)
+                       }
+                       if strings.EqualFold(p.oe[i].Data, p.tok.Data) {
+                               p.oe = p.oe[:i]
+                               break
+                       }
+               }
+               return true
        default:
                // Ignore the token.
        }
        return true
 }
 
+// Section 12.2.5.
+func (p *parser) inForeignContent() bool {
+       if len(p.oe) == 0 {
+               return false
+       }
+       n := p.oe[len(p.oe)-1]
+       if n.Namespace == "" {
+               return false
+       }
+       // TODO: MathML, HTML integration points.
+       // TODO: MathML's annotation-xml combining with SVG's svg.
+       return true
+}
+
 func (p *parser) parse() error {
        // Iterate until EOF. Any other error will cause an early return.
        consumed := true
@@ -1625,7 +1682,11 @@ func (p *parser) parse() error {
                                return err
                        }
                }
-               consumed = p.im(p)
+               if p.inForeignContent() {
+                       consumed = parseForeignContent(p)
+               } else {
+                       consumed = p.im(p)
+               }
        }
        // Loop until the final token (the ErrorToken signifying EOF) is consumed.
        for {
index e887631c63d70d5ff00749f8b8cb82d3f21c7a4e..015b5838f0b50b3a0e8f33e39c545dc68988a60c 100644 (file)
@@ -172,7 +172,8 @@ func TestParser(t *testing.T) {
                {"tests3.dat", -1},
                {"tests4.dat", -1},
                {"tests5.dat", -1},
-               {"tests6.dat", 36},
+               {"tests6.dat", 47},
+               {"tests10.dat", 16},
        }
        for _, tf := range testFiles {
                f, err := os.Open("testdata/webkit/" + tf.filename)
index 9622d7e48eed8dff1547a2a6150a3728f5c9a74e..dcac748967691be048c851ea36441fc991cfdd77 100644 (file)
@@ -183,11 +183,11 @@ const (
 
 func (e *Error) Error() string {
        if e.Line != 0 {
-               return fmt.Sprintf("exp/template/html:%s:%d: %s", e.Name, e.Line, e.Description)
+               return fmt.Sprintf("html/template:%s:%d: %s", e.Name, e.Line, e.Description)
        } else if e.Name != "" {
-               return fmt.Sprintf("exp/template/html:%s: %s", e.Name, e.Description)
+               return fmt.Sprintf("html/template:%s: %s", e.Name, e.Description)
        }
-       return "exp/template/html: " + e.Description
+       return "html/template: " + e.Description
 }
 
 // errorf creates an error given a format string f and args.
index 2f6be3b6c21feee57319a5d3a7436635fdc4c7b6..c6f723ae4a47baff517340b075fca9286d090005 100644 (file)
@@ -486,9 +486,17 @@ func (e *escaper) escapeTree(c context, name string, line int) (context, string)
        }
        t := e.template(name)
        if t == nil {
+               // Two cases: The template exists but is empty, or has never been mentioned at
+               // all. Distinguish the cases in the error messages.
+               if e.tmpl.set[name] != nil {
+                       return context{
+                               state: stateError,
+                               err:   errorf(ErrNoSuchTemplate, line, "%q is an incomplete or empty template", name),
+                       }, dname
+               }
                return context{
                        state: stateError,
-                       err:   errorf(ErrNoSuchTemplate, line, "no such template %s", name),
+                       err:   errorf(ErrNoSuchTemplate, line, "no such template %q", name),
                }, dname
        }
        if dname != name {
index 2d15c71844846f03837a00fabd660b36bea2aa1a..a57f9826b5b5a4e75a5214cc1bf039ed04228082 100644 (file)
@@ -928,7 +928,7 @@ func TestErrors(t *testing.T) {
                },
                {
                        `{{template "foo"}}`,
-                       "z:1: no such template foo",
+                       "z:1: no such template \"foo\"",
                },
                {
                        `<div{{template "y"}}>` +
@@ -944,23 +944,23 @@ func TestErrors(t *testing.T) {
                },
                {
                        `<input type=button value=onclick=>`,
-                       `exp/template/html:z: "=" in unquoted attr: "onclick="`,
+                       `html/template:z: "=" in unquoted attr: "onclick="`,
                },
                {
                        `<input type=button value= onclick=>`,
-                       `exp/template/html:z: "=" in unquoted attr: "onclick="`,
+                       `html/template:z: "=" in unquoted attr: "onclick="`,
                },
                {
                        `<input type=button value= 1+1=2>`,
-                       `exp/template/html:z: "=" in unquoted attr: "1+1=2"`,
+                       `html/template:z: "=" in unquoted attr: "1+1=2"`,
                },
                {
                        "<a class=`foo>",
-                       "exp/template/html:z: \"`\" in unquoted attr: \"`foo\"",
+                       "html/template:z: \"`\" in unquoted attr: \"`foo\"",
                },
                {
                        `<a style=font:'Arial'>`,
-                       `exp/template/html:z: "'" in unquoted attr: "font:'Arial'"`,
+                       `html/template:z: "'" in unquoted attr: "font:'Arial'"`,
                },
                {
                        `<a=foo>`,
diff --git a/libgo/go/image/color/ycbcr.go b/libgo/go/image/color/ycbcr.go
new file mode 100644 (file)
index 0000000..c79816d
--- /dev/null
@@ -0,0 +1,99 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package color
+
+// RGBToYCbCr converts an RGB triple to a Y'CbCr triple. All components lie
+// within the range [0, 255].
+func RGBToYCbCr(r, g, b uint8) (uint8, uint8, uint8) {
+       // The JFIF specification says:
+       //      Y' =  0.2990*R + 0.5870*G + 0.1140*B
+       //      Cb = -0.1687*R - 0.3313*G + 0.5000*B + 128
+       //      Cr =  0.5000*R - 0.4187*G - 0.0813*B + 128
+       // http://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'.
+       r1 := int(r)
+       g1 := int(g)
+       b1 := int(b)
+       yy := (19595*r1 + 38470*g1 + 7471*b1 + 1<<15) >> 16
+       cb := (-11056*r1 - 21712*g1 + 32768*b1 + 257<<15) >> 16
+       cr := (32768*r1 - 27440*g1 - 5328*b1 + 257<<15) >> 16
+       if yy < 0 {
+               yy = 0
+       } else if yy > 255 {
+               yy = 255
+       }
+       if cb < 0 {
+               cb = 0
+       } else if cb > 255 {
+               cb = 255
+       }
+       if cr < 0 {
+               cr = 0
+       } else if cr > 255 {
+               cr = 255
+       }
+       return uint8(yy), uint8(cb), uint8(cr)
+}
+
+// YCbCrToRGB converts a Y'CbCr triple to an RGB triple. All components lie
+// within the range [0, 255].
+func YCbCrToRGB(y, cb, cr uint8) (uint8, uint8, uint8) {
+       // The JFIF specification says:
+       //      R = Y' + 1.40200*(Cr-128)
+       //      G = Y' - 0.34414*(Cb-128) - 0.71414*(Cr-128)
+       //      B = Y' + 1.77200*(Cb-128)
+       // http://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'.
+       yy1 := int(y)<<16 + 1<<15
+       cb1 := int(cb) - 128
+       cr1 := int(cr) - 128
+       r := (yy1 + 91881*cr1) >> 16
+       g := (yy1 - 22554*cb1 - 46802*cr1) >> 16
+       b := (yy1 + 116130*cb1) >> 16
+       if r < 0 {
+               r = 0
+       } else if r > 255 {
+               r = 255
+       }
+       if g < 0 {
+               g = 0
+       } else if g > 255 {
+               g = 255
+       }
+       if b < 0 {
+               b = 0
+       } else if b > 255 {
+               b = 255
+       }
+       return uint8(r), uint8(g), uint8(b)
+}
+
+// YCbCr represents a fully opaque 24-bit Y'CbCr color, having 8 bits each for
+// one luma and two chroma components.
+//
+// JPEG, VP8, the MPEG family and other codecs use this color model. Such
+// codecs often use the terms YUV and Y'CbCr interchangeably, but strictly
+// speaking, the term YUV applies only to analog video signals, and Y' (luma)
+// is Y (luminance) after applying gamma correction.
+//
+// Conversion between RGB and Y'CbCr is lossy and there are multiple, slightly
+// different formulae for converting between the two. This package follows
+// the JFIF specification at http://www.w3.org/Graphics/JPEG/jfif3.pdf.
+type YCbCr struct {
+       Y, Cb, Cr uint8
+}
+
+func (c YCbCr) RGBA() (uint32, uint32, uint32, uint32) {
+       r, g, b := YCbCrToRGB(c.Y, c.Cb, c.Cr)
+       return uint32(r) * 0x101, uint32(g) * 0x101, uint32(b) * 0x101, 0xffff
+}
+
+// YCbCrModel is the Model for Y'CbCr colors.
+var YCbCrModel Model = ModelFunc(func(c Color) Color {
+       if _, ok := c.(YCbCr); ok {
+               return c
+       }
+       r, g, b, _ := c.RGBA()
+       y, u, v := RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8))
+       return YCbCr{y, u, v}
+})
diff --git a/libgo/go/image/color/ycbcr_test.go b/libgo/go/image/color/ycbcr_test.go
new file mode 100644 (file)
index 0000000..92a0e6f
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package color
+
+import (
+       "testing"
+)
+
+func delta(x, y uint8) uint8 {
+       if x >= y {
+               return x - y
+       }
+       return y - x
+}
+
+// Test that a subset of RGB space can be converted to YCbCr and back to within
+// 1/256 tolerance.
+func TestRoundtrip(t *testing.T) {
+       for r := 0; r < 255; r += 7 {
+               for g := 0; g < 255; g += 5 {
+                       for b := 0; b < 255; b += 3 {
+                               r0, g0, b0 := uint8(r), uint8(g), uint8(b)
+                               y, cb, cr := RGBToYCbCr(r0, g0, b0)
+                               r1, g1, b1 := YCbCrToRGB(y, cb, cr)
+                               if delta(r0, r1) > 1 || delta(g0, g1) > 1 || delta(b0, b1) > 1 {
+                                       t.Fatalf("r0, g0, b0 = %d, %d, %d   r1, g1, b1 = %d, %d, %d", r0, g0, b0, r1, g1, b1)
+                               }
+                       }
+               }
+       }
+}
index 2be91185af2e384c0a048216cc6a2de97faf0dd2..4cd2095c441195678f5be74c07e8a4f6e5432ae4 100644 (file)
@@ -7,7 +7,6 @@ package draw
 import (
        "image"
        "image/color"
-       "image/ycbcr"
        "testing"
 )
 
@@ -51,7 +50,7 @@ func bench(b *testing.B, dcm, scm, mcm color.Model, op Op) {
                }
                dst = dst1
        default:
-               panic("unreachable")
+               b.Fatal("unknown destination color model", dcm)
        }
 
        var src image.Image
@@ -97,7 +96,7 @@ func bench(b *testing.B, dcm, scm, mcm color.Model, op Op) {
                        }
                }
                src = src1
-       case ycbcr.YCbCrColorModel:
+       case color.YCbCrModel:
                yy := make([]uint8, srcw*srch)
                cb := make([]uint8, srcw*srch)
                cr := make([]uint8, srcw*srch)
@@ -106,17 +105,17 @@ func bench(b *testing.B, dcm, scm, mcm color.Model, op Op) {
                        cb[i] = uint8(5 * i % 0x100)
                        cr[i] = uint8(7 * i % 0x100)
                }
-               src = &ycbcr.YCbCr{
+               src = &image.YCbCr{
                        Y:              yy,
                        Cb:             cb,
                        Cr:             cr,
                        YStride:        srcw,
                        CStride:        srcw,
-                       SubsampleRatio: ycbcr.SubsampleRatio444,
+                       SubsampleRatio: image.YCbCrSubsampleRatio444,
                        Rect:           image.Rect(0, 0, srcw, srch),
                }
        default:
-               panic("unreachable")
+               b.Fatal("unknown source color model", scm)
        }
 
        var mask image.Image
@@ -137,7 +136,7 @@ func bench(b *testing.B, dcm, scm, mcm color.Model, op Op) {
                }
                mask = mask1
        default:
-               panic("unreachable")
+               b.Fatal("unknown mask color model", mcm)
        }
 
        b.StartTimer()
@@ -177,7 +176,7 @@ func BenchmarkNRGBASrc(b *testing.B) {
 }
 
 func BenchmarkYCbCr(b *testing.B) {
-       bench(b, color.RGBAModel, ycbcr.YCbCrColorModel, nil, Over)
+       bench(b, color.RGBAModel, color.YCbCrModel, nil, Over)
 }
 
 func BenchmarkGlyphOver(b *testing.B) {
index af02639ccd561793b9109feceeb93d0ccb819598..228ed6e719cc5e7242637de6dbebc09b79099455 100644 (file)
@@ -11,7 +11,6 @@ package draw
 import (
        "image"
        "image/color"
-       "image/ycbcr"
 )
 
 // m is the maximum color value returned by image.Color.RGBA.
@@ -81,7 +80,7 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
                                case *image.NRGBA:
                                        drawNRGBAOver(dst0, r, src0, sp)
                                        return
-                               case *ycbcr.YCbCr:
+                               case *image.YCbCr:
                                        drawYCbCr(dst0, r, src0, sp)
                                        return
                                }
@@ -104,7 +103,7 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
                                case *image.NRGBA:
                                        drawNRGBASrc(dst0, r, src0, sp)
                                        return
-                               case *ycbcr.YCbCr:
+                               case *image.YCbCr:
                                        drawYCbCr(dst0, r, src0, sp)
                                        return
                                }
@@ -346,8 +345,8 @@ func drawNRGBASrc(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image
        }
 }
 
-func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *ycbcr.YCbCr, sp image.Point) {
-       // A YCbCr image is always fully opaque, and so if the mask is implicitly nil
+func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Point) {
+       // An image.YCbCr is always fully opaque, and so if the mask is implicitly nil
        // (i.e. fully opaque) then the op is effectively always Src.
        var (
                yy, cb, cr uint8
@@ -357,7 +356,7 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *ycbcr.YCbCr, sp image.Po
        y0 := r.Min.Y - dst.Rect.Min.Y
        y1 := r.Max.Y - dst.Rect.Min.Y
        switch src.SubsampleRatio {
-       case ycbcr.SubsampleRatio422:
+       case image.YCbCrSubsampleRatio422:
                for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
                        dpix := dst.Pix[y*dst.Stride:]
                        for x, sx := x0, sp.X; x != x1; x, sx = x+4, sx+1 {
@@ -365,14 +364,14 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *ycbcr.YCbCr, sp image.Po
                                yy = src.Y[sy*src.YStride+sx]
                                cb = src.Cb[sy*src.CStride+i]
                                cr = src.Cr[sy*src.CStride+i]
-                               rr, gg, bb := ycbcr.YCbCrToRGB(yy, cb, cr)
+                               rr, gg, bb := color.YCbCrToRGB(yy, cb, cr)
                                dpix[x+0] = rr
                                dpix[x+1] = gg
                                dpix[x+2] = bb
                                dpix[x+3] = 255
                        }
                }
-       case ycbcr.SubsampleRatio420:
+       case image.YCbCrSubsampleRatio420:
                for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
                        dpix := dst.Pix[y*dst.Stride:]
                        for x, sx := x0, sp.X; x != x1; x, sx = x+4, sx+1 {
@@ -380,7 +379,7 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *ycbcr.YCbCr, sp image.Po
                                yy = src.Y[sy*src.YStride+sx]
                                cb = src.Cb[j*src.CStride+i]
                                cr = src.Cr[j*src.CStride+i]
-                               rr, gg, bb := ycbcr.YCbCrToRGB(yy, cb, cr)
+                               rr, gg, bb := color.YCbCrToRGB(yy, cb, cr)
                                dpix[x+0] = rr
                                dpix[x+1] = gg
                                dpix[x+2] = bb
@@ -395,7 +394,7 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *ycbcr.YCbCr, sp image.Po
                                yy = src.Y[sy*src.YStride+sx]
                                cb = src.Cb[sy*src.CStride+sx]
                                cr = src.Cr[sy*src.CStride+sx]
-                               rr, gg, bb := ycbcr.YCbCrToRGB(yy, cb, cr)
+                               rr, gg, bb := color.YCbCrToRGB(yy, cb, cr)
                                dpix[x+0] = rr
                                dpix[x+1] = gg
                                dpix[x+2] = bb
index 663ab67a1904337c133d23f6c6904d8a81161156..56a45026b57ca46d6f362bc68db03d186ad1d3b3 100644 (file)
@@ -7,7 +7,6 @@ package draw
 import (
        "image"
        "image/color"
-       "image/ycbcr"
        "testing"
 )
 
@@ -56,13 +55,13 @@ func vgradGreenNRGBA(alpha int) image.Image {
 }
 
 func vgradCr() image.Image {
-       m := &ycbcr.YCbCr{
+       m := &image.YCbCr{
                Y:              make([]byte, 16*16),
                Cb:             make([]byte, 16*16),
                Cr:             make([]byte, 16*16),
                YStride:        16,
                CStride:        16,
-               SubsampleRatio: ycbcr.SubsampleRatio444,
+               SubsampleRatio: image.YCbCrSubsampleRatio444,
                Rect:           image.Rect(0, 0, 16, 16),
        }
        for y := 0; y < 16; y++ {
index c1fc2d590f5534d3fa3ad48321e281b9518f1bba..ed1a962586db5d20f162d997abdf2f2cf45e2d9a 100644 (file)
@@ -11,7 +11,6 @@ import (
        "bufio"
        "image"
        "image/color"
-       "image/ycbcr"
        "io"
 )
 
@@ -97,7 +96,7 @@ type decoder struct {
        r             Reader
        width, height int
        img1          *image.Gray
-       img3          *ycbcr.YCbCr
+       img3          *image.YCbCr
        ri            int // Restart Interval.
        nComp         int
        comp          [nColorComponent]component
@@ -203,20 +202,20 @@ func (d *decoder) makeImg(h0, v0, mxx, myy int) {
                d.img1 = m.SubImage(image.Rect(0, 0, d.width, d.height)).(*image.Gray)
                return
        }
-       var subsampleRatio ycbcr.SubsampleRatio
+       var subsampleRatio image.YCbCrSubsampleRatio
        n := h0 * v0
        switch n {
        case 1:
-               subsampleRatio = ycbcr.SubsampleRatio444
+               subsampleRatio = image.YCbCrSubsampleRatio444
        case 2:
-               subsampleRatio = ycbcr.SubsampleRatio422
+               subsampleRatio = image.YCbCrSubsampleRatio422
        case 4:
-               subsampleRatio = ycbcr.SubsampleRatio420
+               subsampleRatio = image.YCbCrSubsampleRatio420
        default:
                panic("unreachable")
        }
        b := make([]byte, mxx*myy*(1*8*8*n+2*8*8))
-       d.img3 = &ycbcr.YCbCr{
+       d.img3 = &image.YCbCr{
                Y:              b[mxx*myy*(0*8*8*n+0*8*8) : mxx*myy*(1*8*8*n+0*8*8)],
                Cb:             b[mxx*myy*(1*8*8*n+0*8*8) : mxx*myy*(1*8*8*n+1*8*8)],
                Cr:             b[mxx*myy*(1*8*8*n+1*8*8) : mxx*myy*(1*8*8*n+2*8*8)],
@@ -466,7 +465,7 @@ func DecodeConfig(r io.Reader) (image.Config, error) {
        case nGrayComponent:
                return image.Config{color.GrayModel, d.width, d.height}, nil
        case nColorComponent:
-               return image.Config{ycbcr.YCbCrColorModel, d.width, d.height}, nil
+               return image.Config{color.YCbCrModel, d.width, d.height}, nil
        }
        return image.Config{}, FormatError("missing SOF marker")
 }
index fab0bd0bfc11ecbdc68548d03677e2799f89d8a7..71fe37ce7ffc3d87cdc1ffe9785a62b6dddc84a1 100644 (file)
@@ -8,7 +8,7 @@ import (
        "bufio"
        "errors"
        "image"
-       "image/ycbcr"
+       "image/color"
        "io"
 )
 
@@ -379,7 +379,7 @@ func toYCbCr(m image.Image, p image.Point, yBlock, cbBlock, crBlock *block) {
        for j := 0; j < 8; j++ {
                for i := 0; i < 8; i++ {
                        r, g, b, _ := m.At(min(p.X+i, xmax), min(p.Y+j, ymax)).RGBA()
-                       yy, cb, cr := ycbcr.RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8))
+                       yy, cb, cr := color.RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8))
                        yBlock[8*j+i] = int(yy)
                        cbBlock[8*j+i] = int(cb)
                        crBlock[8*j+i] = int(cr)
@@ -404,7 +404,7 @@ func rgbaToYCbCr(m *image.RGBA, p image.Point, yBlock, cbBlock, crBlock *block)
                                sx = xmax
                        }
                        pix := m.Pix[offset+sx*4:]
-                       yy, cb, cr := ycbcr.RGBToYCbCr(pix[0], pix[1], pix[2])
+                       yy, cb, cr := color.RGBToYCbCr(pix[0], pix[1], pix[2])
                        yBlock[8*j+i] = int(yy)
                        cbBlock[8*j+i] = int(cb)
                        crBlock[8*j+i] = int(cr)
index 28e87321361618198a8efc04fa6dc8fd489bc614..e4b56d28847d517e7c9ea0eda7d19763623db55f 100644 (file)
@@ -105,7 +105,7 @@ func BenchmarkEncodeRGBOpaque(b *testing.B) {
                }
        }
        if !img.Opaque() {
-               panic("expected image to be opaque")
+               b.Fatal("expected image to be opaque")
        }
        b.SetBytes(640 * 480 * 4)
        b.StartTimer()
index 1757e14cada5107054bb57baf7ee42e427fc16ed..228ecccfb4f76486457d7ab6b81847abcf22229f 100644 (file)
@@ -125,7 +125,7 @@ func BenchmarkEncodeRGBOpaque(b *testing.B) {
                }
        }
        if !img.Opaque() {
-               panic("expected image to be opaque")
+               b.Fatal("expected image to be opaque")
        }
        b.SetBytes(640 * 480 * 4)
        b.StartTimer()
@@ -138,7 +138,7 @@ func BenchmarkEncodeRGBA(b *testing.B) {
        b.StopTimer()
        img := image.NewRGBA(image.Rect(0, 0, 640, 480))
        if img.Opaque() {
-               panic("expected image to not be opaque")
+               b.Fatal("expected image to not be opaque")
        }
        b.SetBytes(640 * 480 * 4)
        b.StartTimer()
index 1a3d23bbd75548b0dd2c0fc9cc551abb45de1308..ee5dafd9962a75ed37b7fb6dc66587169a356b2a 100644 (file)
@@ -113,7 +113,7 @@ func BenchmarkDecode(b *testing.B) {
        for i := 0; i < b.N; i++ {
                _, err := Decode(r)
                if err != nil {
-                       panic(err)
+                       b.Fatal("Decode:", err)
                }
        }
 }
diff --git a/libgo/go/image/ycbcr.go b/libgo/go/image/ycbcr.go
new file mode 100644 (file)
index 0000000..81f3c9f
--- /dev/null
@@ -0,0 +1,87 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package image
+
+import (
+       "image/color"
+)
+
+// YCbCrSubsampleRatio is the chroma subsample ratio used in a YCbCr image.
+type YCbCrSubsampleRatio int
+
+const (
+       YCbCrSubsampleRatio444 YCbCrSubsampleRatio = iota
+       YCbCrSubsampleRatio422
+       YCbCrSubsampleRatio420
+)
+
+// YCbCr is an in-memory image of Y'CbCr colors. There is one Y sample per
+// pixel, but each Cb and Cr sample can span one or more pixels.
+// YStride is the Y slice index delta between vertically adjacent pixels.
+// CStride is the Cb and Cr slice index delta between vertically adjacent pixels
+// that map to separate chroma samples.
+// It is not an absolute requirement, but YStride and len(Y) are typically
+// multiples of 8, and:
+//     For 4:4:4, CStride == YStride/1 && len(Cb) == len(Cr) == len(Y)/1.
+//     For 4:2:2, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/2.
+//     For 4:2:0, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/4.
+type YCbCr struct {
+       Y              []uint8
+       Cb             []uint8
+       Cr             []uint8
+       YStride        int
+       CStride        int
+       SubsampleRatio YCbCrSubsampleRatio
+       Rect           Rectangle
+}
+
+func (p *YCbCr) ColorModel() color.Model {
+       return color.YCbCrModel
+}
+
+func (p *YCbCr) Bounds() Rectangle {
+       return p.Rect
+}
+
+func (p *YCbCr) At(x, y int) color.Color {
+       if !(Point{x, y}.In(p.Rect)) {
+               return color.YCbCr{}
+       }
+       switch p.SubsampleRatio {
+       case YCbCrSubsampleRatio422:
+               i := x / 2
+               return color.YCbCr{
+                       p.Y[y*p.YStride+x],
+                       p.Cb[y*p.CStride+i],
+                       p.Cr[y*p.CStride+i],
+               }
+       case YCbCrSubsampleRatio420:
+               i, j := x/2, y/2
+               return color.YCbCr{
+                       p.Y[y*p.YStride+x],
+                       p.Cb[j*p.CStride+i],
+                       p.Cr[j*p.CStride+i],
+               }
+       }
+       // Default to 4:4:4 subsampling.
+       return color.YCbCr{
+               p.Y[y*p.YStride+x],
+               p.Cb[y*p.CStride+x],
+               p.Cr[y*p.CStride+x],
+       }
+}
+
+// SubImage returns an image representing the portion of the image p visible
+// through r. The returned value shares pixels with the original image.
+func (p *YCbCr) SubImage(r Rectangle) Image {
+       q := new(YCbCr)
+       *q = *p
+       q.Rect = q.Rect.Intersect(r)
+       return q
+}
+
+func (p *YCbCr) Opaque() bool {
+       return true
+}
diff --git a/libgo/go/image/ycbcr/ycbcr.go b/libgo/go/image/ycbcr/ycbcr.go
deleted file mode 100644 (file)
index 84a35a3..0000000
+++ /dev/null
@@ -1,184 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package ycbcr provides images from the Y'CbCr color model.
-//
-// JPEG, VP8, the MPEG family and other codecs use this color model. Such
-// codecs often use the terms YUV and Y'CbCr interchangeably, but strictly
-// speaking, the term YUV applies only to analog video signals.
-//
-// Conversion between RGB and Y'CbCr is lossy and there are multiple, slightly
-// different formulae for converting between the two. This package follows
-// the JFIF specification at http://www.w3.org/Graphics/JPEG/jfif3.pdf.
-package ycbcr
-
-import (
-       "image"
-       "image/color"
-)
-
-// RGBToYCbCr converts an RGB triple to a YCbCr triple. All components lie
-// within the range [0, 255].
-func RGBToYCbCr(r, g, b uint8) (uint8, uint8, uint8) {
-       // The JFIF specification says:
-       //      Y' =  0.2990*R + 0.5870*G + 0.1140*B
-       //      Cb = -0.1687*R - 0.3313*G + 0.5000*B + 128
-       //      Cr =  0.5000*R - 0.4187*G - 0.0813*B + 128
-       // http://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'.
-       r1 := int(r)
-       g1 := int(g)
-       b1 := int(b)
-       yy := (19595*r1 + 38470*g1 + 7471*b1 + 1<<15) >> 16
-       cb := (-11056*r1 - 21712*g1 + 32768*b1 + 257<<15) >> 16
-       cr := (32768*r1 - 27440*g1 - 5328*b1 + 257<<15) >> 16
-       if yy < 0 {
-               yy = 0
-       } else if yy > 255 {
-               yy = 255
-       }
-       if cb < 0 {
-               cb = 0
-       } else if cb > 255 {
-               cb = 255
-       }
-       if cr < 0 {
-               cr = 0
-       } else if cr > 255 {
-               cr = 255
-       }
-       return uint8(yy), uint8(cb), uint8(cr)
-}
-
-// YCbCrToRGB converts a YCbCr triple to an RGB triple. All components lie
-// within the range [0, 255].
-func YCbCrToRGB(y, cb, cr uint8) (uint8, uint8, uint8) {
-       // The JFIF specification says:
-       //      R = Y' + 1.40200*(Cr-128)
-       //      G = Y' - 0.34414*(Cb-128) - 0.71414*(Cr-128)
-       //      B = Y' + 1.77200*(Cb-128)
-       // http://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'.
-       yy1 := int(y)<<16 + 1<<15
-       cb1 := int(cb) - 128
-       cr1 := int(cr) - 128
-       r := (yy1 + 91881*cr1) >> 16
-       g := (yy1 - 22554*cb1 - 46802*cr1) >> 16
-       b := (yy1 + 116130*cb1) >> 16
-       if r < 0 {
-               r = 0
-       } else if r > 255 {
-               r = 255
-       }
-       if g < 0 {
-               g = 0
-       } else if g > 255 {
-               g = 255
-       }
-       if b < 0 {
-               b = 0
-       } else if b > 255 {
-               b = 255
-       }
-       return uint8(r), uint8(g), uint8(b)
-}
-
-// YCbCrColor represents a fully opaque 24-bit Y'CbCr color, having 8 bits for
-// each of one luma and two chroma components.
-type YCbCrColor struct {
-       Y, Cb, Cr uint8
-}
-
-func (c YCbCrColor) RGBA() (uint32, uint32, uint32, uint32) {
-       r, g, b := YCbCrToRGB(c.Y, c.Cb, c.Cr)
-       return uint32(r) * 0x101, uint32(g) * 0x101, uint32(b) * 0x101, 0xffff
-}
-
-func toYCbCrColor(c color.Color) color.Color {
-       if _, ok := c.(YCbCrColor); ok {
-               return c
-       }
-       r, g, b, _ := c.RGBA()
-       y, u, v := RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8))
-       return YCbCrColor{y, u, v}
-}
-
-// YCbCrColorModel is the color model for YCbCrColor.
-var YCbCrColorModel color.Model = color.ModelFunc(toYCbCrColor)
-
-// SubsampleRatio is the chroma subsample ratio used in a YCbCr image.
-type SubsampleRatio int
-
-const (
-       SubsampleRatio444 SubsampleRatio = iota
-       SubsampleRatio422
-       SubsampleRatio420
-)
-
-// YCbCr is an in-memory image of YCbCr colors. There is one Y sample per pixel,
-// but each Cb and Cr sample can span one or more pixels.
-// YStride is the Y slice index delta between vertically adjacent pixels.
-// CStride is the Cb and Cr slice index delta between vertically adjacent pixels
-// that map to separate chroma samples.
-// It is not an absolute requirement, but YStride and len(Y) are typically
-// multiples of 8, and:
-//     For 4:4:4, CStride == YStride/1 && len(Cb) == len(Cr) == len(Y)/1.
-//     For 4:2:2, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/2.
-//     For 4:2:0, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/4.
-type YCbCr struct {
-       Y              []uint8
-       Cb             []uint8
-       Cr             []uint8
-       YStride        int
-       CStride        int
-       SubsampleRatio SubsampleRatio
-       Rect           image.Rectangle
-}
-
-func (p *YCbCr) ColorModel() color.Model {
-       return YCbCrColorModel
-}
-
-func (p *YCbCr) Bounds() image.Rectangle {
-       return p.Rect
-}
-
-func (p *YCbCr) At(x, y int) color.Color {
-       if !(image.Point{x, y}.In(p.Rect)) {
-               return YCbCrColor{}
-       }
-       switch p.SubsampleRatio {
-       case SubsampleRatio422:
-               i := x / 2
-               return YCbCrColor{
-                       p.Y[y*p.YStride+x],
-                       p.Cb[y*p.CStride+i],
-                       p.Cr[y*p.CStride+i],
-               }
-       case SubsampleRatio420:
-               i, j := x/2, y/2
-               return YCbCrColor{
-                       p.Y[y*p.YStride+x],
-                       p.Cb[j*p.CStride+i],
-                       p.Cr[j*p.CStride+i],
-               }
-       }
-       // Default to 4:4:4 subsampling.
-       return YCbCrColor{
-               p.Y[y*p.YStride+x],
-               p.Cb[y*p.CStride+x],
-               p.Cr[y*p.CStride+x],
-       }
-}
-
-// SubImage returns an image representing the portion of the image p visible
-// through r. The returned value shares pixels with the original image.
-func (p *YCbCr) SubImage(r image.Rectangle) image.Image {
-       q := new(YCbCr)
-       *q = *p
-       q.Rect = q.Rect.Intersect(r)
-       return q
-}
-
-func (p *YCbCr) Opaque() bool {
-       return true
-}
diff --git a/libgo/go/image/ycbcr/ycbcr_test.go b/libgo/go/image/ycbcr/ycbcr_test.go
deleted file mode 100644 (file)
index 2e60a6f..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package ycbcr
-
-import (
-       "testing"
-)
-
-func delta(x, y uint8) uint8 {
-       if x >= y {
-               return x - y
-       }
-       return y - x
-}
-
-// Test that a subset of RGB space can be converted to YCbCr and back to within
-// 1/256 tolerance.
-func TestRoundtrip(t *testing.T) {
-       for r := 0; r < 255; r += 7 {
-               for g := 0; g < 255; g += 5 {
-                       for b := 0; b < 255; b += 3 {
-                               r0, g0, b0 := uint8(r), uint8(g), uint8(b)
-                               y, cb, cr := RGBToYCbCr(r0, g0, b0)
-                               r1, g1, b1 := YCbCrToRGB(y, cb, cr)
-                               if delta(r0, r1) > 1 || delta(g0, g1) > 1 || delta(b0, b1) > 1 {
-                                       t.Fatalf("r0, g0, b0 = %d, %d, %d   r1, g1, b1 = %d, %d, %d", r0, g0, b0, r1, g1, b1)
-                               }
-                       }
-               }
-       }
-}
index 89d6815ad503beaf2e25dd63b1248fc7e9518687..103066817cd97428311d5584dc15f654c2151976 100644 (file)
@@ -37,7 +37,11 @@ func TestReadFile(t *testing.T) {
 }
 
 func TestWriteFile(t *testing.T) {
-       filename := "_test/rumpelstilzchen"
+       f, err := TempFile("", "ioutil-test")
+       if err != nil {
+               t.Fatal(err)
+       }
+       filename := f.Name()
        data := "Programming today is a race between software engineers striving to " +
                "build bigger and better idiot-proof programs, and the Universe trying " +
                "to produce bigger and better idiots. So far, the Universe is winning."
@@ -56,6 +60,7 @@ func TestWriteFile(t *testing.T) {
        }
 
        // cleanup
+       f.Close()
        os.Remove(filename) // ignore error
 }
 
@@ -66,26 +71,28 @@ func TestReadDir(t *testing.T) {
                t.Fatalf("ReadDir %s: error expected, none found", dirname)
        }
 
-       dirname = "."
+       dirname = ".."
        list, err := ReadDir(dirname)
        if err != nil {
                t.Fatalf("ReadDir %s: %v", dirname, err)
        }
 
-       foundTest := false
-       foundTestDir := false
+/* Does not work in gccgo testing environment.
+       foundFile := false
+       foundSubDir := false
        for _, dir := range list {
                switch {
-               case !dir.IsDir() && dir.Name() == "ioutil_test.go":
-                       foundTest = true
-               case dir.IsDir() && dir.Name() == "_test":
-                       foundTestDir = true
+               case !dir.IsDir() && dir.Name() == "io_test.go":
+                       foundFile = true
+               case dir.IsDir() && dir.Name() == "ioutil":
+                       foundSubDir = true
                }
        }
-       if !foundTest {
-               t.Fatalf("ReadDir %s: test file not found", dirname)
+       if !foundFile {
+               t.Fatalf("ReadDir %s: io_test.go file not found", dirname)
        }
-       if !foundTestDir {
-               t.Fatalf("ReadDir %s: _test directory not found", dirname)
+       if !foundSubDir {
+               t.Fatalf("ReadDir %s: ioutil directory not found", dirname)
        }
+*/
 }
index 546bc296a5ffd9d4f4526f133dce0fec944b9f9e..914391af80d65132c8e9cf2151b676aaa20c5518 100644 (file)
@@ -92,11 +92,13 @@ func (w *Writer) Emerg(m string) (err error) {
        _, err = w.writeString(LOG_EMERG, m)
        return err
 }
+
 // Crit logs a message using the LOG_CRIT priority.
 func (w *Writer) Crit(m string) (err error) {
        _, err = w.writeString(LOG_CRIT, m)
        return err
 }
+
 // ERR logs a message using the LOG_ERR priority.
 func (w *Writer) Err(m string) (err error) {
        _, err = w.writeString(LOG_ERR, m)
@@ -114,11 +116,13 @@ func (w *Writer) Notice(m string) (err error) {
        _, err = w.writeString(LOG_NOTICE, m)
        return err
 }
+
 // Info logs a message using the LOG_INFO priority.
 func (w *Writer) Info(m string) (err error) {
        _, err = w.writeString(LOG_INFO, m)
        return err
 }
+
 // Debug logs a message using the LOG_DEBUG priority.
 func (w *Writer) Debug(m string) (err error) {
        _, err = w.writeString(LOG_DEBUG, m)
index 0a3cb0315d24d521a359d3e7c98aa3d52ea4a901..101c8dd85b4ac6f755fef9481738f68fef08804d 100644 (file)
@@ -22,6 +22,7 @@ var vf = []float64{
        1.8253080916808550e+00,
        -8.6859247685756013e+00,
 }
+
 // The expected results below were computed by the high precision calculators
 // at http://keisan.casio.com/.  More exact input values (array vf[], above)
 // were obtained by printing them with "%.26f".  The answers were calculated
@@ -159,6 +160,7 @@ var cos = []float64{
        -2.517729313893103197176091e-01,
        -7.39241351595676573201918e-01,
 }
+
 // Results for 100000 * Pi + vf[i]
 var cosLarge = []float64{
        2.634752141185559426744e-01,
@@ -514,6 +516,7 @@ var sin = []float64{
        9.6778633541687993721617774e-01,
        -6.734405869050344734943028e-01,
 }
+
 // Results for 100000 * Pi + vf[i]
 var sinLarge = []float64{
        -9.646661658548936063912e-01,
@@ -563,6 +566,7 @@ var tan = []float64{
        -3.843885560201130679995041e+00,
        9.10988793377685105753416e-01,
 }
+
 // Results for 100000 * Pi + vf[i]
 var tanLarge = []float64{
        -3.66131656475596512705e+00,
index aa7c19495494fff3778d2d5d326eb789ba8a9371..9c4b730187404fd25278ac3128d68fe19ae494d4 100644 (file)
@@ -9,6 +9,7 @@ import (
        "encoding/gob"
        "encoding/hex"
        "fmt"
+       "math/rand"
        "testing"
        "testing/quick"
 )
@@ -1405,3 +1406,9 @@ func TestIntGobEncoding(t *testing.T) {
                }
        }
 }
+
+func TestIssue2607(t *testing.T) {
+       // This code sequence used to hang.
+       n := NewInt(10)
+       n.Rand(rand.New(rand.NewSource(9)), n)
+}
index ead1a881a6a957d000d764062875b72d2923492a..69681ae2d640b825ba3b1bcbf3be370efea7b38f 100644 (file)
@@ -1196,12 +1196,16 @@ func (x nat) powersOfTwoDecompose() (q nat, k int) {
 // random creates a random integer in [0..limit), using the space in z if
 // possible. n is the bit length of limit.
 func (z nat) random(rand *rand.Rand, limit nat, n int) nat {
+       if alias(z, limit) {
+               z = nil // z is an alias for limit - cannot reuse
+       }
+       z = z.make(len(limit))
+
        bitLengthOfMSW := uint(n % _W)
        if bitLengthOfMSW == 0 {
                bitLengthOfMSW = _W
        }
        mask := Word((1 << bitLengthOfMSW) - 1)
-       z = z.make(len(limit))
 
        for {
                for i := range z {
index e3c6552d9fb3de34cb8a75400dbb4da7066c0db2..25e39273c0c8b48313cd5b394b9984645cc49183 100644 (file)
@@ -5,7 +5,6 @@
 package big
 
 import (
-       "fmt"
        "io"
        "strings"
        "testing"
@@ -402,7 +401,7 @@ func ScanHelper(b *testing.B, base int, x, y Word) {
        var s string
        s = z.string(lowercaseDigits[0:base])
        if t := toString(z, lowercaseDigits[0:base]); t != s {
-               panic(fmt.Sprintf("scanning: got %s; want %s", s, t))
+               b.Fatalf("scanning: got %s; want %s", s, t)
        }
        b.StartTimer()
 
index 2fbe3e7ec5be840cfacd10d4c7ce2ef9ace3254c..ebde7d43681afea2cc5a2c893f61685eddecdc30 100644 (file)
@@ -98,6 +98,7 @@ var _sin = [...]float64{
        8.33333333332211858878E-3,  // 0x3f8111111110f7d0
        -1.66666666666666307295E-1, // 0xbfc5555555555548
 }
+
 // cos coefficients
 var _cos = [...]float64{
        -1.13585365213876817300E-11, // 0xbda8fa49a0861a9b
index 45127ba29df4e5b827f9fc2084ccf4e2a77811c5..2dab1eac78d41d5fb95d31f120659856de67998b 100644 (file)
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build darwin freebsd linux netbsd openbsd plan9
+
 package mime
 
 import (
index fbe6150c26bda4d21e05fe2fa7317a51a4f9e0c5..66aff837d0a412fc2529b874152600fd46e6b5d2 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.
 
-// +build openbsd
+// +build nocgo
 
 // Stub cgo routines for systems that do not use cgo to do network lookups.
 
index 43866dcb51d18ec6c7cbeb1502e3fe6fcde49c54..00acb8477d22dee3b555402b1aa7f50a4f675735 100644 (file)
@@ -4,6 +4,10 @@
 
 package net
 
+import (
+       "time"
+)
+
 func resolveNetAddr(op, net, addr string) (a Addr, err error) {
        if addr == "" {
                return nil, &OpError{op, net, nil, errMissingAddress}
@@ -42,11 +46,15 @@ func resolveNetAddr(op, net, addr string) (a Addr, err error) {
 //     Dial("tcp", "google.com:80")
 //     Dial("tcp", "[de:ad:be:ef::ca:fe]:80")
 //
-func Dial(net, addr string) (c Conn, err error) {
+func Dial(net, addr string) (Conn, error) {
        addri, err := resolveNetAddr("dial", net, addr)
        if err != nil {
                return nil, err
        }
+       return dialAddr(net, addr, addri)
+}
+
+func dialAddr(net, addr string, addri Addr) (c Conn, err error) {
        switch ra := addri.(type) {
        case *TCPAddr:
                c, err = DialTCP(net, nil, ra)
@@ -65,6 +73,62 @@ func Dial(net, addr string) (c Conn, err error) {
        return
 }
 
+// DialTimeout acts like Dial but takes a timeout.
+// The timeout includes name resolution, if required.
+func DialTimeout(net, addr string, timeout time.Duration) (Conn, error) {
+       // TODO(bradfitz): the timeout should be pushed down into the
+       // net package's event loop, so on timeout to dead hosts we
+       // don't have a goroutine sticking around for the default of
+       // ~3 minutes.
+       t := time.NewTimer(timeout)
+       defer t.Stop()
+       type pair struct {
+               Conn
+               error
+       }
+       ch := make(chan pair, 1)
+       resolvedAddr := make(chan Addr, 1)
+       go func() {
+               addri, err := resolveNetAddr("dial", net, addr)
+               if err != nil {
+                       ch <- pair{nil, err}
+                       return
+               }
+               resolvedAddr <- addri // in case we need it for OpError
+               c, err := dialAddr(net, addr, addri)
+               ch <- pair{c, err}
+       }()
+       select {
+       case <-t.C:
+               // Try to use the real Addr in our OpError, if we resolved it
+               // before the timeout. Otherwise we just use stringAddr.
+               var addri Addr
+               select {
+               case a := <-resolvedAddr:
+                       addri = a
+               default:
+                       addri = &stringAddr{net, addr}
+               }
+               err := &OpError{
+                       Op:   "dial",
+                       Net:  net,
+                       Addr: addri,
+                       Err:  &timeoutError{},
+               }
+               return nil, err
+       case p := <-ch:
+               return p.Conn, p.error
+       }
+       panic("unreachable")
+}
+
+type stringAddr struct {
+       net, addr string
+}
+
+func (a stringAddr) Network() string { return a.net }
+func (a stringAddr) String() string  { return a.addr }
+
 // Listen announces on the local network address laddr.
 // The network string net must be a stream-oriented
 // network: "tcp", "tcp4", "tcp6", or "unix", or "unixpacket".
diff --git a/libgo/go/net/dial_test.go b/libgo/go/net/dial_test.go
new file mode 100644 (file)
index 0000000..16b7263
--- /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 net
+
+import (
+       "runtime"
+       "testing"
+       "time"
+)
+
+func newLocalListener(t *testing.T) Listener {
+       ln, err := Listen("tcp", "127.0.0.1:0")
+       if err != nil {
+               ln, err = Listen("tcp6", "[::1]:0")
+       }
+       if err != nil {
+               t.Fatal(err)
+       }
+       return ln
+}
+
+func TestDialTimeout(t *testing.T) {
+       ln := newLocalListener(t)
+       defer ln.Close()
+
+       errc := make(chan error)
+
+       const SOMAXCONN = 0x80 // copied from syscall, but not always available
+       const numConns = SOMAXCONN + 10
+
+       // TODO(bradfitz): It's hard to test this in a portable
+       // way. This is unforunate, but works for now.
+       switch runtime.GOOS {
+       case "linux":
+               // The kernel will start accepting TCP connections before userspace
+               // gets a chance to not accept them, so fire off a bunch to fill up
+               // the kernel's backlog.  Then we test we get a failure after that.
+               for i := 0; i < numConns; i++ {
+                       go func() {
+                               _, err := DialTimeout("tcp", ln.Addr().String(), 200*time.Millisecond)
+                               errc <- err
+                       }()
+               }
+       case "darwin":
+               // At least OS X 10.7 seems to accept any number of
+               // connections, ignoring listen's backlog, so resort
+               // to connecting to a hopefully-dead 127/8 address.
+               go func() {
+                       _, err := DialTimeout("tcp", "127.0.71.111:80", 200*time.Millisecond)
+                       errc <- err
+               }()
+       default:
+               // TODO(bradfitz): this probably doesn't work on
+               // Windows? SOMAXCONN is huge there.  I'm not sure how
+               // listen works there.
+               // OpenBSD may have a reject route to 10/8.
+               // FreeBSD likely works, but is untested.
+               t.Logf("skipping test on %q; untested.", runtime.GOOS)
+               return
+       }
+
+       connected := 0
+       for {
+               select {
+               case <-time.After(15 * time.Second):
+                       t.Fatal("too slow")
+               case err := <-errc:
+                       if err == nil {
+                               connected++
+                               if connected == numConns {
+                                       t.Fatal("all connections connected; expected some to time out")
+                               }
+                       } else {
+                               terr, ok := err.(timeout)
+                               if !ok {
+                                       t.Fatalf("got error %q; want error with timeout interface", err)
+                               }
+                               if !terr.Timeout() {
+                                       t.Fatalf("got error %q; not a timeout", err)
+                               }
+                               // Pass. We saw a timeout error.
+                               return
+                       }
+               }
+       }
+}
index 79a958e3cd0b9d0999d3053cb102530f86c9db95..07e72ccb862cff6ac1f2d461ed3674edd04a829f 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.
 
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
 
 // DNS client: see RFC 1035.
 // Has to be linked into package net for Dial.
index 379fec95b861e264468761320cc7bd675f7d031a..c0ab80288da349f8c9d5028849c210c076a9466b 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.
 
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
 
 // Read system DNS config from /etc/resolv.conf
 
index 5318c51c9a2d7142a8f96a4fa3aa76789a5000ad..3dec9f4beb8b87ba6046ff148c48dac2e0ab7ce1 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.
 
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
 
 package net
 
@@ -377,14 +377,6 @@ func (fd *netFD) CloseWrite() error {
        return fd.shutdown(syscall.SHUT_WR)
 }
 
-type timeoutError struct{}
-
-func (e *timeoutError) Error() string   { return "i/o timeout" }
-func (e *timeoutError) Timeout() bool   { return true }
-func (e *timeoutError) Temporary() bool { return true }
-
-var errTimeout error = &timeoutError{}
-
 func (fd *netFD) Read(p []byte) (n int, err error) {
        if fd == nil {
                return 0, os.EINVAL
index 8e07833882e5a48d88c9158bedaf05b707856297..c8df9c9326a0b8dc418ec56739dd8f532d9f06dd 100644 (file)
@@ -37,11 +37,17 @@ func newpollster() (p *pollster, err error) {
        p = new(pollster)
        var e error
 
-       // The arg to epoll_create is a hint to the kernel
-       // about the number of FDs we will care about.
-       // We don't know, and since 2.6.8 the kernel ignores it anyhow.
-       if p.epfd, e = syscall.EpollCreate(16); e != nil {
-               return nil, os.NewSyscallError("epoll_create", e)
+       if p.epfd, e = syscall.EpollCreate1(syscall.EPOLL_CLOEXEC); e != nil {
+               if e != syscall.ENOSYS {
+                       return nil, os.NewSyscallError("epoll_create1", e)
+               }
+               // The arg to epoll_create is a hint to the kernel
+               // about the number of FDs we will care about.
+               // We don't know, and since 2.6.8 the kernel ignores it anyhow.
+               if p.epfd, e = syscall.EpollCreate(16); e != nil {
+                       return nil, os.NewSyscallError("epoll_create", e)
+               }
+               syscall.CloseOnExec(p.epfd)
        }
        p.events = make(map[int]uint32)
        return p, nil
diff --git a/libgo/go/net/fd_netbsd.go b/libgo/go/net/fd_netbsd.go
new file mode 100644 (file)
index 0000000..31d0744
--- /dev/null
@@ -0,0 +1,116 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Waiting for FDs via kqueue/kevent.
+
+package net
+
+import (
+       "os"
+       "syscall"
+)
+
+type pollster struct {
+       kq       int
+       eventbuf [10]syscall.Kevent_t
+       events   []syscall.Kevent_t
+
+       // An event buffer for AddFD/DelFD.
+       // Must hold pollServer lock.
+       kbuf [1]syscall.Kevent_t
+}
+
+func newpollster() (p *pollster, err error) {
+       p = new(pollster)
+       if p.kq, err = syscall.Kqueue(); err != nil {
+               return nil, os.NewSyscallError("kqueue", err)
+       }
+       syscall.CloseOnExec(p.kq)
+       p.events = p.eventbuf[0:0]
+       return p, nil
+}
+
+func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, error) {
+       // pollServer is locked.
+
+       var kmode int
+       if mode == 'r' {
+               kmode = syscall.EVFILT_READ
+       } else {
+               kmode = syscall.EVFILT_WRITE
+       }
+       ev := &p.kbuf[0]
+       // EV_ADD - add event to kqueue list
+       // EV_ONESHOT - delete the event the first time it triggers
+       flags := syscall.EV_ADD
+       if !repeat {
+               flags |= syscall.EV_ONESHOT
+       }
+       syscall.SetKevent(ev, fd, kmode, flags)
+
+       n, e := syscall.Kevent(p.kq, p.kbuf[:], nil, nil)
+       if e != nil {
+               return false, os.NewSyscallError("kevent", e)
+       }
+       if n != 1 || (ev.Flags&syscall.EV_ERROR) == 0 || int(ev.Ident) != fd || int(ev.Filter) != kmode {
+               return false, os.NewSyscallError("kqueue phase error", e)
+       }
+       if ev.Data != 0 {
+               return false, syscall.Errno(int(ev.Data))
+       }
+       return false, nil
+}
+
+func (p *pollster) DelFD(fd int, mode int) {
+       // pollServer is locked.
+
+       var kmode int
+       if mode == 'r' {
+               kmode = syscall.EVFILT_READ
+       } else {
+               kmode = syscall.EVFILT_WRITE
+       }
+       ev := &p.kbuf[0]
+       // EV_DELETE - delete event from kqueue list
+       syscall.SetKevent(ev, fd, kmode, syscall.EV_DELETE)
+       syscall.Kevent(p.kq, p.kbuf[:], nil, nil)
+}
+
+func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err error) {
+       var t *syscall.Timespec
+       for len(p.events) == 0 {
+               if nsec > 0 {
+                       if t == nil {
+                               t = new(syscall.Timespec)
+                       }
+                       *t = syscall.NsecToTimespec(nsec)
+               }
+
+               s.Unlock()
+               nn, e := syscall.Kevent(p.kq, nil, p.eventbuf[:], t)
+               s.Lock()
+
+               if e != nil {
+                       if e == syscall.EINTR {
+                               continue
+                       }
+                       return -1, 0, os.NewSyscallError("kevent", e)
+               }
+               if nn == 0 {
+                       return -1, 0, nil
+               }
+               p.events = p.eventbuf[0:nn]
+       }
+       ev := &p.events[0]
+       p.events = p.events[1:]
+       fd = int(ev.Ident)
+       if ev.Filter == syscall.EVFILT_READ {
+               mode = 'r'
+       } else {
+               mode = 'w'
+       }
+       return fd, mode, nil
+}
+
+func (p *pollster) Close() error { return os.NewSyscallError("close", syscall.Close(p.kq)) }
index e52ac356b9fd5b086c3bb38e37fb34b28a04bb50..31d0744e2cbe56af2447f2b14a84ce812bf607b1 100644 (file)
@@ -26,6 +26,7 @@ func newpollster() (p *pollster, err error) {
        if p.kq, err = syscall.Kqueue(); err != nil {
                return nil, os.NewSyscallError("kqueue", err)
        }
+       syscall.CloseOnExec(p.kq)
        p.events = p.eventbuf[0:0]
        return p, nil
 }
index bf8cd9dae043e75c23daecb601cd85bd30d892f6..4ac280bd1a34b657ff35043e5471623b4a336bd1 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.
 
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
 
 package net
 
index 211ac44c58a9d92f5c4672d91d1029938acd7274..a4f8f19aac84d4662d083616d3c4c89379f34791 100644 (file)
@@ -38,6 +38,11 @@ type Client struct {
        // If CheckRedirect is nil, the Client uses its default policy,
        // which is to stop after 10 consecutive requests.
        CheckRedirect func(req *Request, via []*Request) error
+
+       // Jar specifies the cookie jar. 
+       // If Jar is nil, cookies are not sent in requests and ignored 
+       // in responses.
+       Jar CookieJar
 }
 
 // DefaultClient is the default Client and is used by Get, Head, and Post.
@@ -180,6 +185,11 @@ func (c *Client) doFollowingRedirects(ireq *Request) (r *Response, err error) {
                return nil, errors.New("http: nil Request.URL")
        }
 
+       jar := c.Jar
+       if jar == nil {
+               jar = blackHoleJar{}
+       }
+
        req := ireq
        urlStr := "" // next relative or absolute URL to fetch (after first request)
        for redirect := 0; ; redirect++ {
@@ -203,12 +213,19 @@ func (c *Client) doFollowingRedirects(ireq *Request) (r *Response, err error) {
                                        break
                                }
                        }
+                       for _, cookie := range jar.Cookies(req.URL) {
+                               req.AddCookie(cookie)
+                       }
                }
 
                urlStr = req.URL.String()
                if r, err = send(req, c.Transport); err != nil {
                        break
                }
+               if c := r.Cookies(); len(c) > 0 {
+                       jar.SetCookies(req.URL, c)
+               }
+
                if shouldRedirect(r.StatusCode) {
                        r.Body.Close()
                        if urlStr = r.Header.Get("Location"); urlStr == "" {
diff --git a/libgo/go/net/http/jar.go b/libgo/go/net/http/jar.go
new file mode 100644 (file)
index 0000000..2c2caa2
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+import (
+       "net/url"
+)
+
+// A CookieJar manages storage and use of cookies in HTTP requests. 
+//
+// Implementations of CookieJar must be safe for concurrent use by multiple
+// goroutines.
+type CookieJar interface {
+       // SetCookies handles the receipt of the cookies in a reply for the 
+       // given URL.  It may or may not choose to save the cookies, depending 
+       // on the jar's policy and implementation. 
+       SetCookies(u *url.URL, cookies []*Cookie)
+
+       // Cookies returns the cookies to send in a request for the given URL.
+       // It is up to the implementation to honor the standard cookie use 
+       // restrictions such as in RFC 6265. 
+       Cookies(u *url.URL) []*Cookie
+}
+
+type blackHoleJar struct{}
+
+func (blackHoleJar) SetCookies(u *url.URL, cookies []*Cookie) {}
+func (blackHoleJar) Cookies(u *url.URL) []*Cookie             { return nil }
index c64fff6109f2270564b11878fce42505d09129f2..ad7e3c02b0ca0f382e3746319cefdcb725d23407 100644 (file)
@@ -219,7 +219,7 @@ func TestReadRequest(t *testing.T) {
                        t.Errorf("#%d: Body = %q want %q", i, body, tt.Body)
                }
                if !reflect.DeepEqual(tt.Trailer, req.Trailer) {
-                       t.Errorf("%#d. Trailers differ.\n got: %v\nwant: %v", i, req.Trailer, tt.Trailer)
+                       t.Errorf("#%d. Trailers differ.\n got: %v\nwant: %v", i, req.Trailer, tt.Trailer)
                }
        }
 }
index 714cb64f47f1b64ff3db51f310a97a053748dfea..7b78645169eb56d65fcc110d2a5c562d709a4067 100644 (file)
@@ -202,8 +202,8 @@ func validateTestMultipartContents(t *testing.T, req *Request, allMem bool) {
        if g, e := req.FormValue("texta"), textaValue; g != e {
                t.Errorf("texta value = %q, want %q", g, e)
        }
-       if g, e := req.FormValue("texta"), textaValue; g != e {
-               t.Errorf("texta value = %q, want %q", g, e)
+       if g, e := req.FormValue("textb"), textbValue; g != e {
+               t.Errorf("textb value = %q, want %q", g, e)
        }
        if g := req.FormValue("missing"); g != "" {
                t.Errorf("missing value = %q, want empty string", g)
@@ -214,14 +214,16 @@ func validateTestMultipartContents(t *testing.T, req *Request, allMem bool) {
                        t.Error(n, " is *os.File, should not be")
                }
        }
-       fd := testMultipartFile(t, req, "filea", "filea.txt", fileaContents)
-       assertMem("filea", fd)
-       fd = testMultipartFile(t, req, "fileb", "fileb.txt", filebContents)
+       fda := testMultipartFile(t, req, "filea", "filea.txt", fileaContents)
+       defer fda.Close()
+       assertMem("filea", fda)
+       fdb := testMultipartFile(t, req, "fileb", "fileb.txt", filebContents)
+       defer fdb.Close()
        if allMem {
-               assertMem("fileb", fd)
+               assertMem("fileb", fdb)
        } else {
-               if _, ok := fd.(*os.File); !ok {
-                       t.Errorf("fileb has unexpected underlying type %T", fd)
+               if _, ok := fdb.(*os.File); !ok {
+                       t.Errorf("fileb has unexpected underlying type %T", fdb)
                }
        }
 
index c68e6614b19079f6c5d27f9e275bbd765eff1063..24e6b50dab87e6d74d128927d8c40a72f9a02587 100644 (file)
@@ -1164,15 +1164,15 @@ func BenchmarkClientServer(b *testing.B) {
        for i := 0; i < b.N; i++ {
                res, err := Get(ts.URL)
                if err != nil {
-                       panic("Get: " + err.Error())
+                       b.Fatal("Get:", err)
                }
                all, err := ioutil.ReadAll(res.Body)
                if err != nil {
-                       panic("ReadAll: " + err.Error())
+                       b.Fatal("ReadAll:", err)
                }
                body := string(all)
                if body != "Hello world.\n" {
-                       panic("Got body: " + body)
+                       b.Fatal("Got body:", body)
                }
        }
 
index e896d43c321f29f8f7c1d05180747369e6a2d3e3..907f80a80f3118522bf0cc16a0dd1113f31919c1 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.
 
-// +build darwin freebsd openbsd
+// +build darwin freebsd netbsd openbsd
 
 // Network interface identification for BSD variants
 
@@ -18,21 +18,16 @@ import (
 // network interfaces.  Otheriwse it returns a mapping of a specific
 // interface.
 func interfaceTable(ifindex int) ([]Interface, error) {
-       var (
-               tab  []byte
-               e    error
-               msgs []syscall.RoutingMessage
-               ift  []Interface
-       )
-
-       tab, e = syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex)
-       if e != nil {
-               return nil, os.NewSyscallError("route rib", e)
+       var ift []Interface
+
+       tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex)
+       if err != nil {
+               return nil, os.NewSyscallError("route rib", err)
        }
 
-       msgs, e = syscall.ParseRoutingMessage(tab)
-       if e != nil {
-               return nil, os.NewSyscallError("route message", e)
+       msgs, err := syscall.ParseRoutingMessage(tab)
+       if err != nil {
+               return nil, os.NewSyscallError("route message", err)
        }
 
        for _, m := range msgs {
@@ -54,9 +49,9 @@ func interfaceTable(ifindex int) ([]Interface, error) {
 func newLink(m *syscall.InterfaceMessage) ([]Interface, error) {
        var ift []Interface
 
-       sas, e := syscall.ParseRoutingSockaddr(m)
-       if e != nil {
-               return nil, os.NewSyscallError("route sockaddr", e)
+       sas, err := syscall.ParseRoutingSockaddr(m)
+       if err != nil {
+               return nil, os.NewSyscallError("route sockaddr", err)
        }
 
        for _, s := range sas {
@@ -108,21 +103,16 @@ func linkFlags(rawFlags int32) Flags {
 // for all network interfaces.  Otherwise it returns addresses
 // for a specific interface.
 func interfaceAddrTable(ifindex int) ([]Addr, error) {
-       var (
-               tab  []byte
-               e    error
-               msgs []syscall.RoutingMessage
-               ifat []Addr
-       )
-
-       tab, e = syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex)
-       if e != nil {
-               return nil, os.NewSyscallError("route rib", e)
+       var ifat []Addr
+
+       tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex)
+       if err != nil {
+               return nil, os.NewSyscallError("route rib", err)
        }
 
-       msgs, e = syscall.ParseRoutingMessage(tab)
-       if e != nil {
-               return nil, os.NewSyscallError("route message", e)
+       msgs, err := syscall.ParseRoutingMessage(tab)
+       if err != nil {
+               return nil, os.NewSyscallError("route message", err)
        }
 
        for _, m := range msgs {
@@ -133,7 +123,7 @@ func interfaceAddrTable(ifindex int) ([]Addr, error) {
                                if err != nil {
                                        return nil, err
                                }
-                               ifat = append(ifat, ifa...)
+                               ifat = append(ifat, ifa)
                        }
                }
        }
@@ -141,32 +131,41 @@ func interfaceAddrTable(ifindex int) ([]Addr, error) {
        return ifat, nil
 }
 
-func newAddr(m *syscall.InterfaceAddrMessage) ([]Addr, error) {
-       var ifat []Addr
+func newAddr(m *syscall.InterfaceAddrMessage) (Addr, error) {
+       ifa := &IPNet{}
 
-       sas, e := syscall.ParseRoutingSockaddr(m)
-       if e != nil {
-               return nil, os.NewSyscallError("route sockaddr", e)
+       sas, err := syscall.ParseRoutingSockaddr(m)
+       if err != nil {
+               return nil, os.NewSyscallError("route sockaddr", err)
        }
 
-       for _, s := range sas {
+       for i, s := range sas {
                switch v := s.(type) {
                case *syscall.SockaddrInet4:
-                       ifa := &IPAddr{IP: IPv4(v.Addr[0], v.Addr[1], v.Addr[2], v.Addr[3])}
-                       ifat = append(ifat, ifa.toAddr())
+                       switch i {
+                       case 0:
+                               ifa.Mask = IPv4Mask(v.Addr[0], v.Addr[1], v.Addr[2], v.Addr[3])
+                       case 1:
+                               ifa.IP = IPv4(v.Addr[0], v.Addr[1], v.Addr[2], v.Addr[3])
+                       }
                case *syscall.SockaddrInet6:
-                       ifa := &IPAddr{IP: make(IP, IPv6len)}
-                       copy(ifa.IP, v.Addr[:])
-                       // NOTE: KAME based IPv6 protcol stack usually embeds
-                       // the interface index in the interface-local or link-
-                       // local address as the kernel-internal form.
-                       if ifa.IP.IsLinkLocalUnicast() {
-                               // remove embedded scope zone ID
-                               ifa.IP[2], ifa.IP[3] = 0, 0
+                       switch i {
+                       case 0:
+                               ifa.Mask = make(IPMask, IPv6len)
+                               copy(ifa.Mask, v.Addr[:])
+                       case 1:
+                               ifa.IP = make(IP, IPv6len)
+                               copy(ifa.IP, v.Addr[:])
+                               // NOTE: KAME based IPv6 protcol stack usually embeds
+                               // the interface index in the interface-local or link-
+                               // local address as the kernel-internal form.
+                               if ifa.IP.IsLinkLocalUnicast() {
+                                       // remove embedded scope zone ID
+                                       ifa.IP[2], ifa.IP[3] = 0, 0
+                               }
                        }
-                       ifat = append(ifat, ifa.toAddr())
                }
        }
 
-       return ifat, nil
+       return ifa, nil
 }
index 96db7186af552d6d53cbb8af04a6aa1980383239..c0887c57efeeb2b2e3e123a8eace09132844caf4 100644 (file)
@@ -17,21 +17,16 @@ import (
 // network interfaces.  Otheriwse it returns a mapping of a specific
 // interface.
 func interfaceTable(ifindex int) ([]Interface, error) {
-       var (
-               ift  []Interface
-               tab  []byte
-               msgs []syscall.NetlinkMessage
-               e    error
-       )
+       var ift []Interface
 
-       tab, e = syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)
-       if e != nil {
-               return nil, os.NewSyscallError("netlink rib", e)
+       tab, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)
+       if err != nil {
+               return nil, os.NewSyscallError("netlink rib", err)
        }
 
-       msgs, e = syscall.ParseNetlinkMessage(tab)
-       if e != nil {
-               return nil, os.NewSyscallError("netlink message", e)
+       msgs, err := syscall.ParseNetlinkMessage(tab)
+       if err != nil {
+               return nil, os.NewSyscallError("netlink message", err)
        }
 
        for _, m := range msgs {
@@ -41,11 +36,11 @@ func interfaceTable(ifindex int) ([]Interface, error) {
                case syscall.RTM_NEWLINK:
                        ifim := (*syscall.IfInfomsg)(unsafe.Pointer(&m.Data[0]))
                        if ifindex == 0 || ifindex == int(ifim.Index) {
-                               attrs, e := syscall.ParseNetlinkRouteAttr(&m)
-                               if e != nil {
-                                       return nil, os.NewSyscallError("netlink routeattr", e)
+                               attrs, err := syscall.ParseNetlinkRouteAttr(&m)
+                               if err != nil {
+                                       return nil, os.NewSyscallError("netlink routeattr", err)
                                }
-                               ifi := newLink(attrs, ifim)
+                               ifi := newLink(ifim, attrs)
                                ift = append(ift, ifi)
                        }
                }
@@ -55,7 +50,7 @@ done:
        return ift, nil
 }
 
-func newLink(attrs []syscall.NetlinkRouteAttr, ifim *syscall.IfInfomsg) Interface {
+func newLink(ifim *syscall.IfInfomsg, attrs []syscall.NetlinkRouteAttr) Interface {
        ifi := Interface{Index: int(ifim.Index), Flags: linkFlags(ifim.Flags)}
        for _, a := range attrs {
                switch a.Attr.Type {
@@ -102,19 +97,19 @@ func linkFlags(rawFlags uint32) Flags {
 // for all network interfaces.  Otherwise it returns addresses
 // for a specific interface.
 func interfaceAddrTable(ifindex int) ([]Addr, error) {
-       tab, e := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC)
-       if e != nil {
-               return nil, os.NewSyscallError("netlink rib", e)
+       tab, err := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC)
+       if err != nil {
+               return nil, os.NewSyscallError("netlink rib", err)
        }
 
-       msgs, e := syscall.ParseNetlinkMessage(tab)
-       if e != nil {
-               return nil, os.NewSyscallError("netlink message", e)
+       msgs, err := syscall.ParseNetlinkMessage(tab)
+       if err != nil {
+               return nil, os.NewSyscallError("netlink message", err)
        }
 
-       ifat, e := addrTable(msgs, ifindex)
-       if e != nil {
-               return nil, e
+       ifat, err := addrTable(msgs, ifindex)
+       if err != nil {
+               return nil, err
        }
 
        return ifat, nil
@@ -130,11 +125,11 @@ func addrTable(msgs []syscall.NetlinkMessage, ifindex int) ([]Addr, error) {
                case syscall.RTM_NEWADDR:
                        ifam := (*syscall.IfAddrmsg)(unsafe.Pointer(&m.Data[0]))
                        if ifindex == 0 || ifindex == int(ifam.Index) {
-                               attrs, e := syscall.ParseNetlinkRouteAttr(&m)
-                               if e != nil {
-                                       return nil, os.NewSyscallError("netlink routeattr", e)
+                               attrs, err := syscall.ParseNetlinkRouteAttr(&m)
+                               if err != nil {
+                                       return nil, os.NewSyscallError("netlink routeattr", err)
                                }
-                               ifat = append(ifat, newAddr(attrs, int(ifam.Family))...)
+                               ifat = append(ifat, newAddr(attrs, int(ifam.Family), int(ifam.Prefixlen)))
                        }
                }
        }
@@ -143,25 +138,23 @@ done:
        return ifat, nil
 }
 
-func newAddr(attrs []syscall.NetlinkRouteAttr, family int) []Addr {
-       var ifat []Addr
-
+func newAddr(attrs []syscall.NetlinkRouteAttr, family, pfxlen int) Addr {
+       ifa := &IPNet{}
        for _, a := range attrs {
                switch a.Attr.Type {
                case syscall.IFA_ADDRESS:
                        switch family {
                        case syscall.AF_INET:
-                               ifa := &IPAddr{IP: IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3])}
-                               ifat = append(ifat, ifa.toAddr())
+                               ifa.IP = IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3])
+                               ifa.Mask = CIDRMask(pfxlen, 8*IPv4len)
                        case syscall.AF_INET6:
-                               ifa := &IPAddr{IP: make(IP, IPv6len)}
+                               ifa.IP = make(IP, IPv6len)
                                copy(ifa.IP, a.Value[:])
-                               ifat = append(ifat, ifa.toAddr())
+                               ifa.Mask = CIDRMask(pfxlen, 8*IPv6len)
                        }
                }
        }
-
-       return ifat
+       return ifa
 }
 
 // If the ifindex is zero, interfaceMulticastAddrTable returns
@@ -169,8 +162,8 @@ func newAddr(attrs []syscall.NetlinkRouteAttr, family int) []Addr {
 // addresses for a specific interface.
 func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
        var (
-               ifi *Interface
                err error
+               ifi *Interface
        )
 
        if ifindex > 0 {
diff --git a/libgo/go/net/interface_netbsd.go b/libgo/go/net/interface_netbsd.go
new file mode 100644 (file)
index 0000000..4150e9a
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2011 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Network interface identification for NetBSD
+
+package net
+
+// If the ifindex is zero, interfaceMulticastAddrTable returns
+// addresses for all network interfaces.  Otherwise it returns
+// addresses for a specific interface.
+func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
+       return nil, nil
+}
index cc614910fac87437c4af166f6c22bd186fbd5440..4ce01dc906189598ac0be0052760d3f707c568bb 100644 (file)
@@ -24,7 +24,7 @@ func sameInterface(i, j *Interface) bool {
 func TestInterfaces(t *testing.T) {
        ift, err := Interfaces()
        if err != nil {
-               t.Fatalf("Interfaces() failed: %v", err)
+               t.Fatalf("Interfaces failed: %v", err)
        }
        t.Logf("table: len/cap = %v/%v\n", len(ift), cap(ift))
 
@@ -43,34 +43,57 @@ func TestInterfaces(t *testing.T) {
                if !sameInterface(ifxn, &ifi) {
                        t.Fatalf("InterfaceByName(%#q) = %v, want %v", ifi.Name, *ifxn, ifi)
                }
-               ifat, err := ifi.Addrs()
-               if err != nil {
-                       t.Fatalf("Interface.Addrs() failed: %v", err)
-               }
-               ifmat, err := ifi.MulticastAddrs()
-               if err != nil {
-                       t.Fatalf("Interface.MulticastAddrs() failed: %v", err)
-               }
                t.Logf("%q: flags %q, ifindex %v, mtu %v\n", ifi.Name, ifi.Flags.String(), ifi.Index, ifi.MTU)
-               for _, ifa := range ifat {
-                       t.Logf("\tinterface address %q\n", ifa.String())
-               }
-               for _, ifma := range ifmat {
-                       t.Logf("\tjoined group address %q\n", ifma.String())
-               }
                t.Logf("\thardware address %q", ifi.HardwareAddr.String())
+               testInterfaceAddrs(t, &ifi)
+               testInterfaceMulticastAddrs(t, &ifi)
        }
 }
 
 func TestInterfaceAddrs(t *testing.T) {
        ifat, err := InterfaceAddrs()
        if err != nil {
-               t.Fatalf("InterfaceAddrs() failed: %v", err)
+               t.Fatalf("InterfaceAddrs failed: %v", err)
        }
        t.Logf("table: len/cap = %v/%v\n", len(ifat), cap(ifat))
+       testAddrs(t, ifat)
+}
+
+func testInterfaceAddrs(t *testing.T, ifi *Interface) {
+       ifat, err := ifi.Addrs()
+       if err != nil {
+               t.Fatalf("Interface.Addrs failed: %v", err)
+       }
+       testAddrs(t, ifat)
+}
+
+func testInterfaceMulticastAddrs(t *testing.T, ifi *Interface) {
+       ifmat, err := ifi.MulticastAddrs()
+       if err != nil {
+               t.Fatalf("Interface.MulticastAddrs failed: %v", err)
+       }
+       testMulticastAddrs(t, ifmat)
+}
 
+func testAddrs(t *testing.T, ifat []Addr) {
        for _, ifa := range ifat {
-               t.Logf("interface address %q\n", ifa.String())
+               switch ifa.(type) {
+               case *IPAddr, *IPNet:
+                       t.Logf("\tinterface address %q\n", ifa.String())
+               default:
+                       t.Errorf("\tunexpected type: %T", ifa)
+               }
+       }
+}
+
+func testMulticastAddrs(t *testing.T, ifmat []Addr) {
+       for _, ifma := range ifmat {
+               switch ifma.(type) {
+               case *IPAddr:
+                       t.Logf("\tjoined group address %q\n", ifma.String())
+               default:
+                       t.Errorf("\tunexpected type: %T", ifma)
+               }
        }
 }
 
index 4a388827875a6e5d0728668719ce3b52201f903f..979d7acd53d949e7184c6bcf1cbe23f363bcd7b9 100644 (file)
@@ -450,6 +450,9 @@ func (n *IPNet) String() string {
        return nn.String() + "/" + itod(uint(l))
 }
 
+// Network returns the address's network name, "ip+net".
+func (n *IPNet) Network() string { return "ip+net" }
+
 // Parse IPv4 address (d.d.d.d).
 func parseIPv4(s string) IP {
        var p [IPv4len]byte
index 60c405ab4ac0233d2eb0c3b452edcaf0f15aff02..67a4049d5d3ff885ccf1dff89467e0bd4ce295dc 100644 (file)
@@ -59,6 +59,7 @@ func parsePingReply(p []byte) (id, seq int) {
 }
 
 var srchost = flag.String("srchost", "", "Source of the ICMP ECHO request")
+
 // 127.0.0.1 because this is an IPv4-specific test.
 var dsthost = flag.String("dsthost", "127.0.0.1", "Destination for the ICMP ECHO request")
 
index d3cb38a6517bd784e6962fb8fbcdd9c27b7998b5..7bb4c7dc0d3d4d4a8ed86d35afa2f7cb14bb325b 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.
 
-// +build darwin freebsd linux openbsd windows
+// +build darwin freebsd linux netbsd openbsd windows
 
 // (Raw) IP sockets
 
index f0ca7dad3457b485d208bf2e0e4437c7c3694b21..d141c050b23042b4e8ae5611401966fd3e6636a7 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.
 
-// +build darwin freebsd linux openbsd windows
+// +build darwin freebsd linux netbsd openbsd windows
 
 package net
 
index aae6d6ceb958af3b343bbf4884543133cc21f3e7..5c475477b8380170c18981effe7a2bf0a71ffd9d 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.
 
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
 
 package net
 
index 48f0ae791c85f3591b3732eabab588df14bb48ed..b236dfdb1dd81ae5daa50537485a521da4cf6702 100644 (file)
@@ -157,6 +157,14 @@ func (e *OpError) Timeout() bool {
        return ok && t.Timeout()
 }
 
+type timeoutError struct{}
+
+func (e *timeoutError) Error() string   { return "i/o timeout" }
+func (e *timeoutError) Timeout() bool   { return true }
+func (e *timeoutError) Temporary() bool { return true }
+
+var errTimeout error = &timeoutError{}
+
 type AddrError struct {
        Err  string
        Addr string
index 035df4a6ff141864f5bf9d5c5b5b6cc2975eda90..a410bb6ce1f86c3ba435feb5dda0bf7cb9689026 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.
 
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
 
 package net
 
index 80597f7555dcc85e021f23e27849eb98d69681ed..16780da1160cd81dc6065924c364ae0f5adcf589 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.
 
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
 
 // Read system port mappings from /etc/services
 
index a52a86e414ea02ebaf0fb95c90e495146e17f358..c1845fa50737bb2f2a72321230b60f20fd58334a 100644 (file)
@@ -516,12 +516,10 @@ func benchmarkEndToEnd(dial func() (*Client, error), b *testing.B) {
                        for atomic.AddInt32(&N, -1) >= 0 {
                                err = client.Call("Arith.Add", args, reply)
                                if err != nil {
-                                       fmt.Printf("Add: expected no error but got string %q", err.Error())
-                                       panic("rpc error")
+                                       b.Fatalf("rpc error: Add: expected no error but got string %q", err.Error())
                                }
                                if reply.C != args.A+args.B {
-                                       fmt.Printf("Add: expected %d got %d", reply.C, args.A+args.B)
-                                       panic("rpc error")
+                                       b.Fatalf("rpc error: Add: expected %d got %d", reply.C, args.A+args.B)
                                }
                        }
                        wg.Done()
@@ -536,8 +534,7 @@ func benchmarkEndToEndAsync(dial func() (*Client, error), b *testing.B) {
        once.Do(startServer)
        client, err := dial()
        if err != nil {
-               fmt.Println("error dialing", err)
-               return
+               b.Fatalf("error dialing:", err)
        }
 
        // Asynchronous calls
@@ -561,12 +558,11 @@ func benchmarkEndToEndAsync(dial func() (*Client, error), b *testing.B) {
                }()
                go func() {
                        for call := range res {
-                               a := call.Args.(*Args).A
-                               b := call.Args.(*Args).B
-                               c := call.Reply.(*Reply).C
-                               if a+b != c {
-                                       fmt.Printf("Add: expected %d got %d", a+b, c)
-                                       panic("incorrect reply")
+                               A := call.Args.(*Args).A
+                               B := call.Args.(*Args).B
+                               C := call.Reply.(*Reply).C
+                               if A+B != C {
+                                       b.Fatalf("incorrect reply: Add: expected %d got %d", A+B, C)
                                }
                                <-gate
                                if atomic.AddInt32(&recv, -1) == 0 {
index b0adea47873a5b0192b7bc12116183ac1abad8c1..ff76ab9cf0e88f711832299ca67af25614f86a61 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.
 
-// +build darwin freebsd openbsd
+// +build darwin freebsd netbsd openbsd
 
 package net
 
index 777f204b18601005bf621ca3872953ce758e8dfe..dc073927eb4211ee5b80d2fb690fb4b966181fe6 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.
 
-// +build darwin freebsd linux openbsd windows
+// +build darwin freebsd linux netbsd openbsd windows
 
 // Sockets
 
index 7025edf7421e89ae1aedf9993bff8a029e92597d..816e4fc3f741cfa97d4ab34905dff9f60712d5de 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.
 
-// +build darwin freebsd openbsd
+// +build darwin freebsd netbsd openbsd
 
 // Sockets for BSD variants
 
index 44890ba66bb53391236128b78914ba8765efcdd2..a7c09c73ed5bd89ac7f49160a4f9a3834dfd545e 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.
 
-// +build darwin freebsd linux openbsd windows
+// +build darwin freebsd linux netbsd openbsd windows
 
 // TCP sockets
 
index 5aefe39867df4479497e18882bb1a7e5ffe3b84a..0460c1c8deeb5557c07524ebed9a39f1ee9e7dd3 100644 (file)
@@ -203,7 +203,7 @@ func TestRFC959Lines(t *testing.T) {
                        t.Errorf("#%d: code=%d, want %d", i, code, tt.wantCode)
                }
                if msg != tt.wantMsg {
-                       t.Errorf("%#d: msg=%q, want %q", i, msg, tt.wantMsg)
+                       t.Errorf("#%d: msg=%q, want %q", i, msg, tt.wantMsg)
                }
        }
 }
index c25ec9c506ac3fc3374482a9045a518d2636abc8..6bb15714e2b0efdc5f0ef224c4875140c4838d34 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.
 
-// +build darwin freebsd linux openbsd windows
+// +build darwin freebsd linux netbsd openbsd windows
 
 // UDP sockets
 
index 929f6409a4f0836fe18c719b36b0b133b4de7cb7..10632c1412e16558bebd92fad91b2580a307e06e 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.
 
-// +build darwin freebsd linux openbsd windows
+// +build darwin freebsd linux netbsd openbsd windows
 
 // Unix domain sockets
 
index 9a04360dd11a719676a8e95275f2e0d8b8d7f552..180dac4d455db6ff0decf8c5df9de52f23c0daf9 100644 (file)
@@ -321,8 +321,7 @@ func BenchmarkLiteral(b *testing.B) {
        b.StartTimer()
        for i := 0; i < b.N; i++ {
                if !re.MatchString(x) {
-                       println("no match!")
-                       break
+                       b.Fatal("no match!")
                }
        }
 }
@@ -334,8 +333,7 @@ func BenchmarkNotLiteral(b *testing.B) {
        b.StartTimer()
        for i := 0; i < b.N; i++ {
                if !re.MatchString(x) {
-                       println("no match!")
-                       break
+                       b.Fatal("no match!")
                }
        }
 }
@@ -347,8 +345,7 @@ func BenchmarkMatchClass(b *testing.B) {
        b.StartTimer()
        for i := 0; i < b.N; i++ {
                if !re.MatchString(x) {
-                       println("no match!")
-                       break
+                       b.Fatal("no match!")
                }
        }
 }
@@ -362,8 +359,7 @@ func BenchmarkMatchClass_InRange(b *testing.B) {
        b.StartTimer()
        for i := 0; i < b.N; i++ {
                if !re.MatchString(x) {
-                       println("no match!")
-                       break
+                       b.Fatal("no match!")
                }
        }
 }
index a6e0c3e1b4e23915637628aa0481a592f724f000..f42a61a1b13be5fdc51c111e8556a8d6c8d09719 100644 (file)
@@ -10,6 +10,7 @@ import (
        "fmt"
        "io"
        "io/ioutil"
+       "os"
        "strings"
        "testing"
 )
@@ -463,23 +464,32 @@ func TestAll(t *testing.T) {
        // Parse
        testAll(t, func(test *Test) (*Template, error) { return Parse(test.in, formatters) })
        // ParseFile
+       f, err := ioutil.TempFile("", "template-test")
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer func() {
+               name := f.Name()
+               f.Close()
+               os.Remove(name)
+       }()
        testAll(t, func(test *Test) (*Template, error) {
-               err := ioutil.WriteFile("_test/test.tmpl", []byte(test.in), 0600)
+               err := ioutil.WriteFile(f.Name(), []byte(test.in), 0600)
                if err != nil {
                        t.Error("unexpected write error:", err)
                        return nil, err
                }
-               return ParseFile("_test/test.tmpl", formatters)
+               return ParseFile(f.Name(), formatters)
        })
        // tmpl.ParseFile
        testAll(t, func(test *Test) (*Template, error) {
-               err := ioutil.WriteFile("_test/test.tmpl", []byte(test.in), 0600)
+               err := ioutil.WriteFile(f.Name(), []byte(test.in), 0600)
                if err != nil {
                        t.Error("unexpected write error:", err)
                        return nil, err
                }
                tmpl := New(formatters)
-               return tmpl, tmpl.ParseFile("_test/test.tmpl")
+               return tmpl, tmpl.ParseFile(f.Name())
        })
 }
 
index e4dff835d89975033f728f3aa105465382cf6288..e7a29554c15af5a2fd6597922ad80dc09791a1da 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.
 
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
 
 package os
 
index dbe1b9a8d5eeb37cd7b7a6bc32796ca78586dc26..ebbe4369703328d92f313754c5e54b715f0bad1b 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.
 
-// +build darwin freebsd linux openbsd windows
+// +build darwin freebsd linux netbsd openbsd windows
 
 package os
 
index 4c95c1b0dac5a750592365eb4311895e378f9e98..a00fdad497faa94a336242014ad6d29a9f51e22b 100644 (file)
@@ -67,6 +67,9 @@ type Cmd struct {
        // ExtraFiles specifies additional open files to be inherited by the
        // new process. It does not include standard input, standard output, or
        // standard error. If non-nil, entry i becomes file descriptor 3+i.
+       //
+       // BUG: on OS X 10.6, child processes may sometimes inherit extra fds.
+       // http://golang.org/issue/2603
        ExtraFiles []*os.File
 
        // SysProcAttr holds optional, operating system-specific attributes.
index 8f63653c014d58d9f7708592b7516318fd964932..c68498047faa6ff159c85edaf06ac74b28ad6154 100644 (file)
@@ -10,6 +10,9 @@ import (
        "fmt"
        "io"
        "io/ioutil"
+       "net"
+       "net/http"
+       "net/http/httptest"
        "os"
        "runtime"
        "strconv"
@@ -18,7 +21,7 @@ import (
 )
 
 func helperCommand(s ...string) *Cmd {
-       cs := []string{"-test.run=exec.TestHelperProcess", "--"}
+       cs := []string{"-test.run=TestHelperProcess", "--"}
        cs = append(cs, s...)
        cmd := Command(os.Args[0], cs...)
        cmd.Env = append([]string{"GO_WANT_HELPER_PROCESS=1"}, os.Environ()...)
@@ -146,6 +149,23 @@ func TestExtraFiles(t *testing.T) {
                t.Logf("no operating system support; skipping")
                return
        }
+
+       // Force network usage, to verify the epoll (or whatever) fd
+       // doesn't leak to the child,
+       ln, err := net.Listen("tcp", "127.0.0.1:0")
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer ln.Close()
+
+       // Force TLS root certs to be loaded (which might involve
+       // cgo), to make sure none of that potential C code leaks fds.
+       ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+               w.Write([]byte("Hello"))
+       }))
+       defer ts.Close()
+       http.Get(ts.URL) // ignore result; just calling to force root cert loading
+
        tf, err := ioutil.TempFile("", "")
        if err != nil {
                t.Fatalf("TempFile: %v", err)
@@ -167,7 +187,7 @@ func TestExtraFiles(t *testing.T) {
        c.ExtraFiles = []*os.File{tf}
        bs, err := c.CombinedOutput()
        if err != nil {
-               t.Fatalf("CombinedOutput: %v", err)
+               t.Fatalf("CombinedOutput: %v; output %q", err, bs)
        }
        if string(bs) != text {
                t.Errorf("got %q; want %q", string(bs), text)
@@ -246,6 +266,32 @@ func TestHelperProcess(*testing.T) {
                        fmt.Printf("ReadAll from fd 3: %v", err)
                        os.Exit(1)
                }
+               switch runtime.GOOS {
+               case "darwin":
+                       // TODO(bradfitz): broken? Sometimes.
+                       // http://golang.org/issue/2603
+                       // Skip this additional part of the test for now.
+               default:
+                       // Now verify that there are no other open fds.
+                       var files []*os.File
+                       for wantfd := os.Stderr.Fd() + 2; wantfd <= 100; wantfd++ {
+                               f, err := os.Open(os.Args[0])
+                               if err != nil {
+                                       fmt.Printf("error opening file with expected fd %d: %v", wantfd, err)
+                                       os.Exit(1)
+                               }
+                               if got := f.Fd(); got != wantfd {
+                                       fmt.Printf("leaked parent file. fd = %d; want %d\n", got, wantfd)
+                                       out, _ := Command("lsof", "-p", fmt.Sprint(os.Getpid())).CombinedOutput()
+                                       fmt.Print(string(out))
+                                       os.Exit(1)
+                               }
+                               files = append(files, f)
+                       }
+                       for _, f := range files {
+                               f.Close()
+                       }
+               }
                os.Stderr.Write(bs)
        case "exit":
                n, _ := strconv.Atoi(args[0])
index 9665ea8f4138a516a01200cf130b1e5537f57246..a221137230db379b04bab33eb6620c4e281e519b 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.
 
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
 
 package exec
 
index 8b08eebd0daf0fb195b6f237ec1aa0d26d135839..218b8cdc1d68593602671e13e22c9c6e63c2f7fb 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.
 
-// +build darwin freebsd linux openbsd windows
+// +build darwin freebsd linux netbsd openbsd windows
 
 package os
 
@@ -24,7 +24,7 @@ func (sig UnixSignal) String() string {
 // StartProcess starts a new process with the program, arguments and attributes
 // specified by name, argv and attr.
 //
-// StartProcess is a low-level interface. The exec package provides
+// StartProcess is a low-level interface. The os/exec package provides
 // higher-level interfaces.
 func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) {
        sysattr := &syscall.ProcAttr{
@@ -56,7 +56,7 @@ func (p *Process) Kill() error {
 // If successful, Exec never returns.  If it fails, it returns an error.
 //
 // To run a child process, see StartProcess (for a low-level interface)
-// or the exec package (for higher-level interfaces).
+// or the os/exec package (for higher-level interfaces).
 func Exec(name string, argv []string, envv []string) error {
        if envv == nil {
                envv = Environ()
index 3dcac414c5ab41cba7b14b23c36eac96239ef343..375813895d97d472fad7871a91c0a6ffdb7c457e 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.
 
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
 
 package os
 
index a4ab5d6ae25d36b4d6572d20193ee991234b1854..8231ef4817c96ee5ccd4edccacc184ce34700ebd 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.
 
-// +build darwin freebsd linux openbsd windows
+// +build darwin freebsd linux netbsd openbsd windows
 
 package os
 
@@ -24,39 +24,6 @@ func epipecheck(file *File, e error) {
        }
 }
 
-// Remove removes the named file or directory.
-func Remove(name string) error {
-       // System call interface forces us to know
-       // whether name is a file or directory.
-       // Try both: it is cheaper on average than
-       // doing a Stat plus the right one.
-       e := syscall.Unlink(name)
-       if e == nil {
-               return nil
-       }
-       e1 := syscall.Rmdir(name)
-       if e1 == nil {
-               return nil
-       }
-
-       // Both failed: figure out which error to return.
-       // OS X and Linux differ on whether unlink(dir)
-       // returns EISDIR, so can't use that.  However,
-       // both agree that rmdir(file) returns ENOTDIR,
-       // so we can use that to decide which error is real.
-       // Rmdir might also return ENOTDIR if given a bad
-       // file path, like /etc/passwd/foo, but in that case,
-       // both errors will be ENOTDIR, so it's okay to
-       // use the error from unlink.
-       // For windows syscall.ENOTDIR is set
-       // to syscall.ERROR_PATH_NOT_FOUND, hopefully it should
-       // do the trick.
-       if e1 != syscall.ENOTDIR {
-               e = e1
-       }
-       return &PathError{"remove", name, e}
-}
-
 // LinkError records an error during a link or symlink or rename
 // system call and the paths that caused it.
 type LinkError struct {
index 671d1a4cb62e73772180f5780af36fc40c63129f..069baa14d4e19fb16f92b08a8c5b6f652b427617 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.
 
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
 
 package os
 
@@ -67,8 +67,13 @@ func OpenFile(name string, flag int, perm uint32) (file *File, err error) {
        }
 
        // There's a race here with fork/exec, which we are
-       // content to live with.  See ../syscall/exec.go
-       if syscall.O_CLOEXEC == 0 { // O_CLOEXEC not supported
+       // content to live with.  See ../syscall/exec_unix.go.
+       // On OS X 10.6, the O_CLOEXEC flag is not respected.
+       // On OS X 10.7, the O_CLOEXEC flag works.
+       // Without a cheap & reliable way to detect 10.6 vs 10.7 at
+       // runtime, we just always call syscall.CloseOnExec on Darwin.
+       // Once >=10.7 is prevalent, this extra call can removed.
+       if syscall.O_CLOEXEC == 0 || runtime.GOOS == "darwin" { // O_CLOEXEC not supported
                syscall.CloseOnExec(r)
        }
 
@@ -216,6 +221,36 @@ func Truncate(name string, size int64) error {
        return nil
 }
 
+// Remove removes the named file or directory.
+func Remove(name string) error {
+       // System call interface forces us to know
+       // whether name is a file or directory.
+       // Try both: it is cheaper on average than
+       // doing a Stat plus the right one.
+       e := syscall.Unlink(name)
+       if e == nil {
+               return nil
+       }
+       e1 := syscall.Rmdir(name)
+       if e1 == nil {
+               return nil
+       }
+
+       // Both failed: figure out which error to return.
+       // OS X and Linux differ on whether unlink(dir)
+       // returns EISDIR, so can't use that.  However,
+       // both agree that rmdir(file) returns ENOTDIR,
+       // so we can use that to decide which error is real.
+       // Rmdir might also return ENOTDIR if given a bad
+       // file path, like /etc/passwd/foo, but in that case,
+       // both errors will be ENOTDIR, so it's okay to
+       // use the error from unlink.
+       if e1 != syscall.ENOTDIR {
+               e = e1
+       }
+       return &PathError{"remove", name, e}
+}
+
 // basename removes trailing slashes and the leading directory name from path name
 func basename(name string) string {
        i := len(name) - 1
index 299d2e86155bcd8010a03333ceaab6ea4de73453..9a6099080341e4e874fda6c2941fb186abb1f8bd 100644 (file)
@@ -917,7 +917,7 @@ func TestReadAt(t *testing.T) {
        b := make([]byte, 5)
        n, err := f.ReadAt(b, 7)
        if err != nil || n != len(b) {
-               t.Fatalf("ReadAt 7: %d, %r", n, err)
+               t.Fatalf("ReadAt 7: %d, %v", n, err)
        }
        if string(b) != "world" {
                t.Fatalf("ReadAt 7: have %q want %q", string(b), "world")
index 3109a8171a58bc6607907ca27cf49da2e196fd1e..1f800d78ccaee956ec3ece4b5338b18d67db17b0 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.
 
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
 
 package os_test
 
index 33045b60c4580887dde1be5f8badf5e14b7df8e9..30a167b1adc0b3e4761f784b220fc013cdb61dcf 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.
 
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
 
 package os
 
index 520f3f8a9ea49c4a1543dd1cac7d05568eb1e7e2..bce4530e7bc73c2a05fc65f83f9ea4c5ba079551 100644 (file)
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build darwin freebsd linux netbsd openbsd
+
 // Package signal implements operating system-independent signal handling.
 package signal
 
@@ -31,3 +33,5 @@ func init() {
        Incoming = ch
        go process(ch)
 }
+
+// BUG(rsc): This package is unavailable on Plan 9 and Windows.
index 00eb29578f970bc212534f2117d87b4333154faa..4568aa9518e7b538fbf569ca92c1664eaec3d652 100644 (file)
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build darwin freebsd linux netbsd openbsd
+
 package signal
 
 import (
index c6a6de5c816f6d39826afa182610022a4a36ab2c..d196469e7d48d00c1d0e4390028a8109a23997f4 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.
 
-// +build darwin freebsd openbsd
+// +build darwin freebsd netbsd openbsd
 
 // os code shared between *BSD systems including OS X (Darwin)
 // and FreeBSD.
index 0999dedbb95c81809603d93534bb1750cd6ce3db..42fa557445f2c21476995473d75b8006352de080 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.
 
-// +build openbsd plan9 windows
+// +build nocgo windows
 
 package user
 
index 89886cb03cf2c0f9d0f5628eab30e08abb9b1441..602a3da2cd4ec72a63c475dd36658e2757dbf693 100644 (file)
@@ -3,6 +3,7 @@
 // license that can be found in the LICENSE file.
 
 // +build darwin freebsd linux
+// +build cgo
 
 package user
 
index e3d6c342ca6878ca209f54a10f8d9c81bf0f3996..3dc52aab4672873a6ab1a00b1d7f66b4174bdd5c 100644 (file)
@@ -147,6 +147,7 @@ func SplitList(path string) []string {
 // separating it into a directory and file name component.
 // If there is no Separator in path, Split returns an empty dir
 // and file set to path.
+// The returned values have the property that path = dir+file.
 func Split(path string) (dir, file string) {
        vol := VolumeName(path)
        i := len(path) - 1
@@ -262,6 +263,8 @@ func Abs(path string) (string, error) {
 // Rel returns a relative path that is lexically equivalent to targpath when
 // joined to basepath with an intervening separator. That is,
 // Join(basepath, Rel(basepath, targpath)) is equivalent to targpath itself.
+// On success, the returned path will always be relative to basepath,
+// even if basepath and targpath share no elements.
 // An error is returned if targpath can't be made relative to basepath or if
 // knowing the current working directory would be necessary to compute it.
 func Rel(basepath, targpath string) (string, error) {
@@ -423,6 +426,8 @@ func Base(path string) string {
        for len(path) > 0 && os.IsPathSeparator(path[len(path)-1]) {
                path = path[0 : len(path)-1]
        }
+       // Throw away volume name
+       path = path[len(VolumeName(path)):]
        // Find the last element
        i := len(path) - 1
        for i >= 0 && !os.IsPathSeparator(path[i]) {
@@ -437,3 +442,25 @@ func Base(path string) string {
        }
        return path
 }
+
+// Dir returns the all but the last element of path, typically the path's directory.
+// Trailing path separators are removed before processing.
+// If the path is empty, Dir returns ".".
+// If the path consists entirely of separators, Dir returns a single separator.
+// The returned path does not end in a separator unless it is the root directory.
+func Dir(path string) string {
+       vol := VolumeName(path)
+       i := len(path) - 1
+       for i >= len(vol) && !os.IsPathSeparator(path[i]) {
+               i--
+       }
+       dir := Clean(path[len(vol) : i+1])
+       last := len(dir) - 1
+       if last > 0 && os.IsPathSeparator(dir[last]) {
+               dir = dir[:last]
+       }
+       if dir == "" {
+               dir = "."
+       }
+       return vol + dir
+}
index b5b0dedcd40970e9a985e77f09d3fa4e25239b12..63adcb88c46a94d98606b90a7bfb0855cc77cb3b 100644 (file)
@@ -422,14 +422,77 @@ var basetests = []PathTest{
        {"a/b/c.x", "c.x"},
 }
 
+var winbasetests = []PathTest{
+       {`c:\`, `\`},
+       {`c:.`, `.`},
+       {`c:\a\b`, `b`},
+       {`c:a\b`, `b`},
+       {`c:a\b\c`, `c`},
+       {`\\host\share\`, `\`},
+       {`\\host\share\a`, `a`},
+       {`\\host\share\a\b`, `b`},
+}
+
 func TestBase(t *testing.T) {
-       for _, test := range basetests {
-               if s := filepath.ToSlash(filepath.Base(test.path)); s != test.result {
+       tests := basetests
+       if runtime.GOOS == "windows" {
+               // make unix tests work on windows
+               for i, _ := range tests {
+                       tests[i].result = filepath.Clean(tests[i].result)
+               }
+               // add windows specific tests
+               tests = append(tests, winbasetests...)
+       }
+       for _, test := range tests {
+               if s := filepath.Base(test.path); s != test.result {
                        t.Errorf("Base(%q) = %q, want %q", test.path, s, test.result)
                }
        }
 }
 
+var dirtests = []PathTest{
+       {"", "."},
+       {".", "."},
+       {"/.", "/"},
+       {"/", "/"},
+       {"////", "/"},
+       {"/foo", "/"},
+       {"x/", "x"},
+       {"abc", "."},
+       {"abc/def", "abc"},
+       {"a/b/.x", "a/b"},
+       {"a/b/c.", "a/b"},
+       {"a/b/c.x", "a/b"},
+}
+
+var windirtests = []PathTest{
+       {`c:\`, `c:\`},
+       {`c:.`, `c:.`},
+       {`c:\a\b`, `c:\a`},
+       {`c:a\b`, `c:a`},
+       {`c:a\b\c`, `c:a\b`},
+       {`\\host\share\`, `\\host\share\`},
+       {`\\host\share\a`, `\\host\share\`},
+       {`\\host\share\a\b`, `\\host\share\a`},
+}
+
+func TestDir(t *testing.T) {
+       tests := dirtests
+       if runtime.GOOS == "windows" {
+               // make unix tests work on windows
+               for i, _ := range tests {
+                       tests[i].result = filepath.Clean(tests[i].result)
+               }
+               // add windows specific tests
+               tests = append(tests, windirtests...)
+       }
+       for _, test := range tests {
+               if s := filepath.Dir(test.path); s != test.result {
+                       t.Errorf("Dir(%q) = %q, want %q", test.path, s, test.result)
+               }
+       }
+}
+
 type IsAbsTest struct {
        path  string
        isAbs bool
index daf0eb2af7c2ef8664105030135f49c0c8dd9d05..c5ac71efe218f28117543436082e636140ed22e4 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.
 
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
 
 package filepath
 
index 235384667c678c2c1630368ee30640cd630926c8..20d89c9ff0cbcbee125e1c88ffa198cc67563ef5 100644 (file)
@@ -160,3 +160,21 @@ func Base(path string) string {
 func IsAbs(path string) bool {
        return len(path) > 0 && path[0] == '/'
 }
+
+// Dir returns the all but the last element of path, typically the path's directory.
+// Trailing path separators are removed before processing.
+// If the path is empty, Dir returns ".".
+// If the path consists entirely of separators, Dir returns a single separator.
+// The returned path does not end in a separator unless it is the root directory.
+func Dir(path string) string {
+       dir, _ := Split(path)
+       dir = Clean(dir)
+       last := len(dir) - 1
+       if last > 0 && dir[last] == '/' {
+               dir = dir[:last]
+       }
+       if dir == "" {
+               dir = "."
+       }
+       return dir
+}
index 1fd57cc800ec7eccff173f03239463f2bfc81c0c..77f080433b667719f103ec09f9f57656b4d4c907 100644 (file)
@@ -8,11 +8,11 @@ import (
        "testing"
 )
 
-type CleanTest struct {
-       path, clean string
+type PathTest struct {
+       path, result string
 }
 
-var cleantests = []CleanTest{
+var cleantests = []PathTest{
        // Already clean
        {"", "."},
        {"abc", "abc"},
@@ -64,8 +64,8 @@ var cleantests = []CleanTest{
 
 func TestClean(t *testing.T) {
        for _, test := range cleantests {
-               if s := Clean(test.path); s != test.clean {
-                       t.Errorf("Clean(%q) = %q, want %q", test.path, s, test.clean)
+               if s := Clean(test.path); s != test.result {
+                       t.Errorf("Clean(%q) = %q, want %q", test.path, s, test.result)
                }
        }
 }
@@ -148,7 +148,7 @@ func TestExt(t *testing.T) {
        }
 }
 
-var basetests = []CleanTest{
+var basetests = []PathTest{
        // Already clean
        {"", "."},
        {".", "."},
@@ -165,8 +165,31 @@ var basetests = []CleanTest{
 
 func TestBase(t *testing.T) {
        for _, test := range basetests {
-               if s := Base(test.path); s != test.clean {
-                       t.Errorf("Base(%q) = %q, want %q", test.path, s, test.clean)
+               if s := Base(test.path); s != test.result {
+                       t.Errorf("Base(%q) = %q, want %q", test.path, s, test.result)
+               }
+       }
+}
+
+var dirtests = []PathTest{
+       {"", "."},
+       {".", "."},
+       {"/.", "/"},
+       {"/", "/"},
+       {"////", "/"},
+       {"/foo", "/"},
+       {"x/", "x"},
+       {"abc", "."},
+       {"abc/def", "abc"},
+       {"a/b/.x", "a/b"},
+       {"a/b/c.", "a/b"},
+       {"a/b/c.x", "a/b"},
+}
+
+func TestDir(t *testing.T) {
+       for _, test := range dirtests {
+               if s := Dir(test.path); s != test.result {
+                       t.Errorf("Dir(%q) = %q, want %q", test.path, s, test.result)
                }
        }
 }
index 8810796daf2d4176dad4e665d5a7044aa06cc94d..e729510b5134da56ca57dd188ca648cea92e34bd 100644 (file)
@@ -324,8 +324,7 @@ func BenchmarkLiteral(b *testing.B) {
        b.StartTimer()
        for i := 0; i < b.N; i++ {
                if !re.MatchString(x) {
-                       println("no match!")
-                       break
+                       b.Fatalf("no match!")
                }
        }
 }
@@ -337,8 +336,7 @@ func BenchmarkNotLiteral(b *testing.B) {
        b.StartTimer()
        for i := 0; i < b.N; i++ {
                if !re.MatchString(x) {
-                       println("no match!")
-                       break
+                       b.Fatalf("no match!")
                }
        }
 }
@@ -350,8 +348,7 @@ func BenchmarkMatchClass(b *testing.B) {
        b.StartTimer()
        for i := 0; i < b.N; i++ {
                if !re.MatchString(x) {
-                       println("no match!")
-                       break
+                       b.Fatalf("no match!")
                }
        }
 }
@@ -365,8 +362,7 @@ func BenchmarkMatchClass_InRange(b *testing.B) {
        b.StartTimer()
        for i := 0; i < b.N; i++ {
                if !re.MatchString(x) {
-                       println("no match!")
-                       break
+                       b.Fatalf("no match!")
                }
        }
 }
index 312bf0275fd49de4940b01f6eb2399bf4c3d43d8..e668574a514389377c9baf2e95cc204799b91c46 100644 (file)
@@ -673,7 +673,7 @@ func benchmark(b *testing.B, re string, n int) {
        b.SetBytes(int64(n))
        for i := 0; i < b.N; i++ {
                if r.Match(t) {
-                       panic("match!")
+                       b.Fatal("match!")
                }
        }
 }
index 83ee170cbab2e863e5aa96b51d2029bce289883e..4aa4ca6d7da78e25bdec3b83f1a4695b487d8dfc 100644 (file)
@@ -240,14 +240,18 @@ func (p StringSlice) Sort() { Sort(p) }
 
 // Ints sorts a slice of ints in increasing order.
 func Ints(a []int) { Sort(IntSlice(a)) }
+
 // Float64s sorts a slice of float64s in increasing order.
 func Float64s(a []float64) { Sort(Float64Slice(a)) }
+
 // Strings sorts a slice of strings in increasing order.
 func Strings(a []string) { Sort(StringSlice(a)) }
 
 // IntsAreSorted tests whether a slice of ints is sorted in increasing order.
 func IntsAreSorted(a []int) bool { return IsSorted(IntSlice(a)) }
+
 // Float64sAreSorted tests whether a slice of float64s is sorted in increasing order.
 func Float64sAreSorted(a []float64) bool { return IsSorted(Float64Slice(a)) }
+
 // StringsAreSorted tests whether a slice of strings is sorted in increasing order.
 func StringsAreSorted(a []string) bool { return IsSorted(StringSlice(a)) }
index 8bda89088bfed43079d1b0cba980596b907e56c1..42fc431db8a7cf153d1b02d2633dc9f6aaa8b2e9 100644 (file)
@@ -263,6 +263,18 @@ func (d *decimal) atof32int() float32 {
        return f
 }
 
+// Reads a uint64 decimal mantissa, which might be truncated.
+func (d *decimal) atou64() (mant uint64, digits int) {
+       const uint64digits = 19
+       for i, c := range d.d[:d.nd] {
+               if i == uint64digits {
+                       return mant, i
+               }
+               mant = 10*mant + uint64(c-'0')
+       }
+       return mant, d.nd
+}
+
 // Exact powers of 10.
 var float64pow10 = []float64{
        1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
@@ -375,6 +387,17 @@ func atof64(s string) (f float64, err error) {
                if f, ok := d.atof64(); ok {
                        return f, nil
                }
+
+               // Try another fast path.
+               ext := new(extFloat)
+               if ok := ext.AssignDecimal(&d); ok {
+                       b, ovf := ext.floatBits()
+                       f = math.Float64frombits(b)
+                       if ovf {
+                               err = rangeError(fnParseFloat, s)
+                       }
+                       return f, err
+               }
        }
        b, ovf := d.floatBits(&float64info)
        f = math.Float64frombits(b)
index 4d5ce1714f4f7c7d3b11250106bee866b9cb8528..3fa637d2bc6b42a261f99fb2891a94d7cefdd83c 100644 (file)
@@ -5,9 +5,12 @@
 package strconv_test
 
 import (
+       "math"
+       "math/rand"
        "reflect"
        . "strconv"
        "testing"
+       "time"
 )
 
 type atofTest struct {
@@ -111,8 +114,22 @@ var atoftests = []atofTest{
        {"2.2250738585072012e-308", "2.2250738585072014e-308", nil},
        // http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
        {"2.2250738585072011e-308", "2.225073858507201e-308", nil},
+
+       // A very large number (initially wrongly parsed by the fast algorithm).
+       {"4.630813248087435e+307", "4.630813248087435e+307", nil},
+}
+
+type atofSimpleTest struct {
+       x float64
+       s string
 }
 
+var (
+       atofRandomTests        []atofSimpleTest
+       benchmarksRandomBits   [1024]string
+       benchmarksRandomNormal [1024]string
+)
+
 func init() {
        // The atof routines return NumErrors wrapping
        // the error and the string.  Convert the table above.
@@ -122,6 +139,31 @@ func init() {
                        test.err = &NumError{"ParseFloat", test.in, test.err}
                }
        }
+
+       // Generate random inputs for tests and benchmarks
+       rand.Seed(time.Now().UnixNano())
+       if testing.Short() {
+               atofRandomTests = make([]atofSimpleTest, 100)
+       } else {
+               atofRandomTests = make([]atofSimpleTest, 10000)
+       }
+       for i := range atofRandomTests {
+               n := uint64(rand.Uint32())<<32 | uint64(rand.Uint32())
+               x := math.Float64frombits(n)
+               s := FormatFloat(x, 'g', -1, 64)
+               atofRandomTests[i] = atofSimpleTest{x, s}
+       }
+
+       for i := range benchmarksRandomBits {
+               bits := uint64(rand.Uint32())<<32 | uint64(rand.Uint32())
+               x := math.Float64frombits(bits)
+               benchmarksRandomBits[i] = FormatFloat(x, 'g', -1, 64)
+       }
+
+       for i := range benchmarksRandomNormal {
+               x := rand.NormFloat64()
+               benchmarksRandomNormal[i] = FormatFloat(x, 'g', -1, 64)
+       }
 }
 
 func testAtof(t *testing.T, opt bool) {
@@ -156,6 +198,19 @@ func TestAtof(t *testing.T) { testAtof(t, true) }
 
 func TestAtofSlow(t *testing.T) { testAtof(t, false) }
 
+func TestAtofRandom(t *testing.T) {
+       for _, test := range atofRandomTests {
+               x, _ := ParseFloat(test.s, 64)
+               switch {
+               default:
+                       t.Errorf("number %s badly parsed as %b (expected %b)", test.s, x, test.x)
+               case x == test.x:
+               case math.IsNaN(test.x) && math.IsNaN(x):
+               }
+       }
+       t.Logf("tested %d random numbers", len(atofRandomTests))
+}
+
 func BenchmarkAtof64Decimal(b *testing.B) {
        for i := 0; i < b.N; i++ {
                ParseFloat("33909", 64)
@@ -179,3 +234,15 @@ func BenchmarkAtof64Big(b *testing.B) {
                ParseFloat("123456789123456789123456789", 64)
        }
 }
+
+func BenchmarkAtof64RandomBits(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               ParseFloat(benchmarksRandomBits[i%1024], 64)
+       }
+}
+
+func BenchmarkAtof64RandomFloats(b *testing.B) {
+       for i := 0; i < b.N; i++ {
+               ParseFloat(benchmarksRandomNormal[i%1024], 64)
+       }
+}
index 541553097bbb3a2e9fcb1449bc2cc34710693277..cc5591a8d8f19a3d629cdbee9097af526c916d59 100644 (file)
@@ -14,9 +14,9 @@ package strconv
 type decimal struct {
        // TODO(rsc): Can make d[] a bit smaller and add
        // truncated bool;
-       d   [2000]byte // digits
-       nd  int        // number of digits used
-       dp  int        // decimal point
+       d   [800]byte // digits
+       nd  int       // number of digits used
+       dp  int       // decimal point
        neg bool
 }
 
diff --git a/libgo/go/strconv/extfloat.go b/libgo/go/strconv/extfloat.go
new file mode 100644 (file)
index 0000000..980052a
--- /dev/null
@@ -0,0 +1,311 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strconv
+
+import "math"
+
+// An extFloat represents an extended floating-point number, with more
+// precision than a float64. It does not try to save bits: the
+// number represented by the structure is mant*(2^exp), with a negative
+// sign if neg is true.
+type extFloat struct {
+       mant uint64
+       exp  int
+       neg  bool
+}
+
+// Powers of ten taken from double-conversion library.
+// http://code.google.com/p/double-conversion/
+const (
+       firstPowerOfTen = -348
+       stepPowerOfTen  = 8
+)
+
+var smallPowersOfTen = [...]extFloat{
+       {1 << 63, -63, false},        // 1
+       {0xa << 60, -60, false},      // 1e1
+       {0x64 << 57, -57, false},     // 1e2
+       {0x3e8 << 54, -54, false},    // 1e3
+       {0x2710 << 50, -50, false},   // 1e4
+       {0x186a0 << 47, -47, false},  // 1e5
+       {0xf4240 << 44, -44, false},  // 1e6
+       {0x989680 << 40, -40, false}, // 1e7
+}
+
+var powersOfTen = [...]extFloat{
+       {0xfa8fd5a0081c0288, -1220, false}, // 10^-348
+       {0xbaaee17fa23ebf76, -1193, false}, // 10^-340
+       {0x8b16fb203055ac76, -1166, false}, // 10^-332
+       {0xcf42894a5dce35ea, -1140, false}, // 10^-324
+       {0x9a6bb0aa55653b2d, -1113, false}, // 10^-316
+       {0xe61acf033d1a45df, -1087, false}, // 10^-308
+       {0xab70fe17c79ac6ca, -1060, false}, // 10^-300
+       {0xff77b1fcbebcdc4f, -1034, false}, // 10^-292
+       {0xbe5691ef416bd60c, -1007, false}, // 10^-284
+       {0x8dd01fad907ffc3c, -980, false},  // 10^-276
+       {0xd3515c2831559a83, -954, false},  // 10^-268
+       {0x9d71ac8fada6c9b5, -927, false},  // 10^-260
+       {0xea9c227723ee8bcb, -901, false},  // 10^-252
+       {0xaecc49914078536d, -874, false},  // 10^-244
+       {0x823c12795db6ce57, -847, false},  // 10^-236
+       {0xc21094364dfb5637, -821, false},  // 10^-228
+       {0x9096ea6f3848984f, -794, false},  // 10^-220
+       {0xd77485cb25823ac7, -768, false},  // 10^-212
+       {0xa086cfcd97bf97f4, -741, false},  // 10^-204
+       {0xef340a98172aace5, -715, false},  // 10^-196
+       {0xb23867fb2a35b28e, -688, false},  // 10^-188
+       {0x84c8d4dfd2c63f3b, -661, false},  // 10^-180
+       {0xc5dd44271ad3cdba, -635, false},  // 10^-172
+       {0x936b9fcebb25c996, -608, false},  // 10^-164
+       {0xdbac6c247d62a584, -582, false},  // 10^-156
+       {0xa3ab66580d5fdaf6, -555, false},  // 10^-148
+       {0xf3e2f893dec3f126, -529, false},  // 10^-140
+       {0xb5b5ada8aaff80b8, -502, false},  // 10^-132
+       {0x87625f056c7c4a8b, -475, false},  // 10^-124
+       {0xc9bcff6034c13053, -449, false},  // 10^-116
+       {0x964e858c91ba2655, -422, false},  // 10^-108
+       {0xdff9772470297ebd, -396, false},  // 10^-100
+       {0xa6dfbd9fb8e5b88f, -369, false},  // 10^-92
+       {0xf8a95fcf88747d94, -343, false},  // 10^-84
+       {0xb94470938fa89bcf, -316, false},  // 10^-76
+       {0x8a08f0f8bf0f156b, -289, false},  // 10^-68
+       {0xcdb02555653131b6, -263, false},  // 10^-60
+       {0x993fe2c6d07b7fac, -236, false},  // 10^-52
+       {0xe45c10c42a2b3b06, -210, false},  // 10^-44
+       {0xaa242499697392d3, -183, false},  // 10^-36
+       {0xfd87b5f28300ca0e, -157, false},  // 10^-28
+       {0xbce5086492111aeb, -130, false},  // 10^-20
+       {0x8cbccc096f5088cc, -103, false},  // 10^-12
+       {0xd1b71758e219652c, -77, false},   // 10^-4
+       {0x9c40000000000000, -50, false},   // 10^4
+       {0xe8d4a51000000000, -24, false},   // 10^12
+       {0xad78ebc5ac620000, 3, false},     // 10^20
+       {0x813f3978f8940984, 30, false},    // 10^28
+       {0xc097ce7bc90715b3, 56, false},    // 10^36
+       {0x8f7e32ce7bea5c70, 83, false},    // 10^44
+       {0xd5d238a4abe98068, 109, false},   // 10^52
+       {0x9f4f2726179a2245, 136, false},   // 10^60
+       {0xed63a231d4c4fb27, 162, false},   // 10^68
+       {0xb0de65388cc8ada8, 189, false},   // 10^76
+       {0x83c7088e1aab65db, 216, false},   // 10^84
+       {0xc45d1df942711d9a, 242, false},   // 10^92
+       {0x924d692ca61be758, 269, false},   // 10^100
+       {0xda01ee641a708dea, 295, false},   // 10^108
+       {0xa26da3999aef774a, 322, false},   // 10^116
+       {0xf209787bb47d6b85, 348, false},   // 10^124
+       {0xb454e4a179dd1877, 375, false},   // 10^132
+       {0x865b86925b9bc5c2, 402, false},   // 10^140
+       {0xc83553c5c8965d3d, 428, false},   // 10^148
+       {0x952ab45cfa97a0b3, 455, false},   // 10^156
+       {0xde469fbd99a05fe3, 481, false},   // 10^164
+       {0xa59bc234db398c25, 508, false},   // 10^172
+       {0xf6c69a72a3989f5c, 534, false},   // 10^180
+       {0xb7dcbf5354e9bece, 561, false},   // 10^188
+       {0x88fcf317f22241e2, 588, false},   // 10^196
+       {0xcc20ce9bd35c78a5, 614, false},   // 10^204
+       {0x98165af37b2153df, 641, false},   // 10^212
+       {0xe2a0b5dc971f303a, 667, false},   // 10^220
+       {0xa8d9d1535ce3b396, 694, false},   // 10^228
+       {0xfb9b7cd9a4a7443c, 720, false},   // 10^236
+       {0xbb764c4ca7a44410, 747, false},   // 10^244
+       {0x8bab8eefb6409c1a, 774, false},   // 10^252
+       {0xd01fef10a657842c, 800, false},   // 10^260
+       {0x9b10a4e5e9913129, 827, false},   // 10^268
+       {0xe7109bfba19c0c9d, 853, false},   // 10^276
+       {0xac2820d9623bf429, 880, false},   // 10^284
+       {0x80444b5e7aa7cf85, 907, false},   // 10^292
+       {0xbf21e44003acdd2d, 933, false},   // 10^300
+       {0x8e679c2f5e44ff8f, 960, false},   // 10^308
+       {0xd433179d9c8cb841, 986, false},   // 10^316
+       {0x9e19db92b4e31ba9, 1013, false},  // 10^324
+       {0xeb96bf6ebadf77d9, 1039, false},  // 10^332
+       {0xaf87023b9bf0ee6b, 1066, false},  // 10^340
+}
+
+// floatBits returns the bits of the float64 that best approximates
+// the extFloat passed as receiver. Overflow is set to true if
+// the resulting float64 is Â±Inf.
+func (f *extFloat) floatBits() (bits uint64, overflow bool) {
+       flt := &float64info
+       f.Normalize()
+
+       exp := f.exp + 63
+
+       // Exponent too small.
+       if exp < flt.bias+1 {
+               n := flt.bias + 1 - exp
+               f.mant >>= uint(n)
+               exp += n
+       }
+
+       // Extract 1+flt.mantbits bits.
+       mant := f.mant >> (63 - flt.mantbits)
+       if f.mant&(1<<(62-flt.mantbits)) != 0 {
+               // Round up.
+               mant += 1
+       }
+
+       // Rounding might have added a bit; shift down.
+       if mant == 2<<flt.mantbits {
+               mant >>= 1
+               exp++
+       }
+
+       // Infinities.
+       if exp-flt.bias >= 1<<flt.expbits-1 {
+               goto overflow
+       }
+
+       // Denormalized?
+       if mant&(1<<flt.mantbits) == 0 {
+               exp = flt.bias
+       }
+       goto out
+
+overflow:
+       // Â±Inf
+       mant = 0
+       exp = 1<<flt.expbits - 1 + flt.bias
+       overflow = true
+
+out:
+       // Assemble bits.
+       bits = mant & (uint64(1)<<flt.mantbits - 1)
+       bits |= uint64((exp-flt.bias)&(1<<flt.expbits-1)) << flt.mantbits
+       if f.neg {
+               bits |= 1 << (flt.mantbits + flt.expbits)
+       }
+       return
+}
+
+// Assign sets f to the value of x.
+func (f *extFloat) Assign(x float64) {
+       if x < 0 {
+               x = -x
+               f.neg = true
+       }
+       x, f.exp = math.Frexp(x)
+       f.mant = uint64(x * float64(1<<64))
+       f.exp -= 64
+}
+
+// Normalize normalizes f so that the highest bit of the mantissa is
+// set, and returns the number by which the mantissa was left-shifted.
+func (f *extFloat) Normalize() uint {
+       if f.mant == 0 {
+               return 0
+       }
+       exp_before := f.exp
+       for f.mant < (1 << 55) {
+               f.mant <<= 8
+               f.exp -= 8
+       }
+       for f.mant < (1 << 63) {
+               f.mant <<= 1
+               f.exp -= 1
+       }
+       return uint(exp_before - f.exp)
+}
+
+// Multiply sets f to the product f*g: the result is correctly rounded,
+// but not normalized.
+func (f *extFloat) Multiply(g extFloat) {
+       fhi, flo := f.mant>>32, uint64(uint32(f.mant))
+       ghi, glo := g.mant>>32, uint64(uint32(g.mant))
+
+       // Cross products.
+       cross1 := fhi * glo
+       cross2 := flo * ghi
+
+       // f.mant*g.mant is fhi*ghi << 64 + (cross1+cross2) << 32 + flo*glo
+       f.mant = fhi*ghi + (cross1 >> 32) + (cross2 >> 32)
+       rem := uint64(uint32(cross1)) + uint64(uint32(cross2)) + ((flo * glo) >> 32)
+       // Round up.
+       rem += (1 << 31)
+
+       f.mant += (rem >> 32)
+       f.exp = f.exp + g.exp + 64
+}
+
+var uint64pow10 = [...]uint64{
+       1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+       1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+}
+
+// AssignDecimal sets f to an approximate value of the decimal d. It
+// returns true if the value represented by f is guaranteed to be the
+// best approximation of d after being rounded to a float64. 
+func (f *extFloat) AssignDecimal(d *decimal) (ok bool) {
+       const uint64digits = 19
+       const errorscale = 8
+       mant10, digits := d.atou64()
+       exp10 := d.dp - digits
+       errors := 0 // An upper bound for error, computed in errorscale*ulp.
+
+       if digits < d.nd {
+               // the decimal number was truncated.
+               errors += errorscale / 2
+       }
+
+       f.mant = mant10
+       f.exp = 0
+       f.neg = d.neg
+
+       // Multiply by powers of ten.
+       i := (exp10 - firstPowerOfTen) / stepPowerOfTen
+       if exp10 < firstPowerOfTen || i >= len(powersOfTen) {
+               return false
+       }
+       adjExp := (exp10 - firstPowerOfTen) % stepPowerOfTen
+
+       // We multiply by exp%step
+       if digits+adjExp <= uint64digits {
+               // We can multiply the mantissa
+               f.mant *= uint64(float64pow10[adjExp])
+               f.Normalize()
+       } else {
+               f.Normalize()
+               f.Multiply(smallPowersOfTen[adjExp])
+               errors += errorscale / 2
+       }
+
+       // We multiply by 10 to the exp - exp%step.
+       f.Multiply(powersOfTen[i])
+       if errors > 0 {
+               errors += 1
+       }
+       errors += errorscale / 2
+
+       // Normalize
+       shift := f.Normalize()
+       errors <<= shift
+
+       // Now f is a good approximation of the decimal.
+       // Check whether the error is too large: that is, if the mantissa
+       // is perturbated by the error, the resulting float64 will change.
+       // The 64 bits mantissa is 1 + 52 bits for float64 + 11 extra bits.
+       //
+       // In many cases the approximation will be good enough.
+       const denormalExp = -1023 - 63
+       flt := &float64info
+       var extrabits uint
+       if f.exp <= denormalExp {
+               extrabits = uint(63 - flt.mantbits + 1 + uint(denormalExp-f.exp))
+       } else {
+               extrabits = uint(63 - flt.mantbits)
+       }
+
+       halfway := uint64(1) << (extrabits - 1)
+       mant_extra := f.mant & (1<<extrabits - 1)
+
+       // Do a signed comparison here! If the error estimate could make
+       // the mantissa round differently for the conversion to double,
+       // then we can't give a definite answer.
+       if int64(halfway)-int64(errors) < int64(mant_extra) &&
+               int64(mant_extra) < int64(halfway)+int64(errors) {
+               return false
+       }
+       return true
+}
index 692e3e4087520ff28c8ac79b796b515a4abef4b0..f4434fd51753c8a96e0ecee3406f09af2c8ae063 100644 (file)
@@ -40,11 +40,7 @@ var float64info = floatInfo{52, 11, -1023}
 // For 'e', 'E', and 'f' it is the number of digits after the decimal point.
 // For 'g' and 'G' it is the total number of digits.
 // The special precision -1 uses the smallest number of digits
-// necessary such that Atof32 will return f exactly.
-//
-// Ftoa32(f) is not the same as Ftoa64(float32(f)),
-// because correct rounding and the number of digits
-// needed to identify f depend on the precision of the representation.
+// necessary such that ParseFloat will return f exactly.
 func FormatFloat(f float64, fmt byte, prec, bitSize int) string {
        return string(genericFtoa(make([]byte, 0, max(prec+4, 24)), f, fmt, prec, bitSize))
 }
index 8866d220c00d92b8362e314a8b37f2a7ba0d0646..54046d68aa0073dea15d6f1cc47e44d6cb8d36dc 100644 (file)
@@ -8,7 +8,6 @@ import (
        "bytes"
        "io"
        "reflect"
-       "strconv"
        . "strings"
        "testing"
        "unicode"
@@ -143,7 +142,7 @@ const benchmarkString = "some_text=some☺value"
 
 func BenchmarkIndexRune(b *testing.B) {
        if got := IndexRune(benchmarkString, '☺'); got != 14 {
-               panic("wrong index: got=" + strconv.Itoa(got))
+               b.Fatalf("wrong index: expected 14, got=%d", got)
        }
        for i := 0; i < b.N; i++ {
                IndexRune(benchmarkString, '☺')
@@ -152,7 +151,7 @@ func BenchmarkIndexRune(b *testing.B) {
 
 func BenchmarkIndexRuneFastPath(b *testing.B) {
        if got := IndexRune(benchmarkString, 'v'); got != 17 {
-               panic("wrong index: got=" + strconv.Itoa(got))
+               b.Fatalf("wrong index: expected 17, got=%d", got)
        }
        for i := 0; i < b.N; i++ {
                IndexRune(benchmarkString, 'v')
@@ -161,7 +160,7 @@ func BenchmarkIndexRuneFastPath(b *testing.B) {
 
 func BenchmarkIndex(b *testing.B) {
        if got := Index(benchmarkString, "v"); got != 17 {
-               panic("wrong index: got=" + strconv.Itoa(got))
+               b.Fatalf("wrong index: expected 17, got=%d", got)
        }
        for i := 0; i < b.N; i++ {
                Index(benchmarkString, "v")
index f94b7233b6716d66a5be7a6d19f2cd374c2a447d..f98036c42cdbfba560211f276ed85b080f942ae2 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.
 
-// +build darwin freebsd openbsd
+// +build darwin freebsd netbsd openbsd
 
 // Berkeley packet filter for BSD variants
 
index df259097c6aabed3ca32ee7fd7338b0291064a58..3ba0fb1b098d30be0b72c3730299a382ce825cfa 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.
 
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
 
 // Unix environment variables.
 
index c9814b7050efcccf6209c729f0c6fbef7192e366..0cd37c4a0b529c48c1c0cc369b54643937d956e9 100644 (file)
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build darwin freebsd linux netbsd openbsd
+
 // Fork, exec, wait, etc.
 
 package syscall
index bc4c15e950bfa8c48bb9065d86393f4525df0c97..e17d976b1548723cd1b19cc42c9662c7ac988173 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.
 
-// +build darwin freebsd openbsd
+// +build darwin freebsd netbsd openbsd
 
 // Routing sockets and messages
 
@@ -85,8 +85,8 @@ func (m *RouteMessage) sockaddr() []Sockaddr {
                rsa := (*RawSockaddr)(unsafe.Pointer(&buf[0]))
                switch i {
                case RTAX_DST, RTAX_GATEWAY:
-                       sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
-                       if e != nil {
+                       sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
+                       if err != nil {
                                return nil
                        }
                        if i == RTAX_DST {
@@ -128,8 +128,8 @@ func (m *InterfaceMessage) sockaddr() (sas []Sockaddr) {
        if m.Header.Addrs&RTA_IFP == 0 {
                return nil
        }
-       sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(&m.Data[0])))
-       if e != nil {
+       sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(&m.Data[0])))
+       if err != nil {
                return nil
        }
        return append(sas, sa)
@@ -157,12 +157,21 @@ func (m *InterfaceAddrMessage) sockaddr() (sas []Sockaddr) {
                rsa := (*RawSockaddr)(unsafe.Pointer(&buf[0]))
                switch i {
                case RTAX_IFA:
-                       sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
-                       if e != nil {
+                       sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
+                       if err != nil {
                                return nil
                        }
                        sas = append(sas, sa)
-               case RTAX_NETMASK, RTAX_BRD:
+               case RTAX_NETMASK:
+                       if rsa.Family == AF_UNSPEC {
+                               rsa.Family = AF_INET // an old fasion, AF_UNSPEC means AF_INET
+                       }
+                       sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
+                       if err != nil {
+                               return nil
+                       }
+                       sas = append(sas, sa)
+               case RTAX_BRD:
                        // nothing to do
                }
                buf = buf[rsaAlignOf(int(rsa.Len)):]
diff --git a/libgo/go/syscall/route_netbsd.go b/libgo/go/syscall/route_netbsd.go
new file mode 100644 (file)
index 0000000..d6d9031
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright 2011 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Routing sockets and messages for NetBSD
+
+package syscall
+
+import (
+       "unsafe"
+)
+
+func (any *anyMessage) toRoutingMessage(buf []byte) RoutingMessage {
+       switch any.Type {
+       case RTM_ADD, RTM_DELETE, RTM_CHANGE, RTM_GET, RTM_LOSING, RTM_REDIRECT, RTM_MISS, RTM_LOCK, RTM_RESOLVE:
+               p := (*RouteMessage)(unsafe.Pointer(any))
+               rtm := &RouteMessage{}
+               rtm.Header = p.Header
+               rtm.Data = buf[SizeofRtMsghdr:any.Msglen]
+               return rtm
+       case RTM_IFINFO:
+               p := (*InterfaceMessage)(unsafe.Pointer(any))
+               ifm := &InterfaceMessage{}
+               ifm.Header = p.Header
+               ifm.Data = buf[SizeofIfMsghdr:any.Msglen]
+               return ifm
+       case RTM_NEWADDR, RTM_DELADDR:
+               p := (*InterfaceAddrMessage)(unsafe.Pointer(any))
+               ifam := &InterfaceAddrMessage{}
+               ifam.Header = p.Header
+               ifam.Data = buf[SizeofIfaMsghdr:any.Msglen]
+               return ifam
+       }
+       return nil
+}
index 84c1383d7e28e1e65bc11ee876d7df6932adedf7..d279decb65a5c31eec8628ee8310a84470f42981 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.
 
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
 
 // Socket control messages
 
index 212e0b2d4181ffa466c163e04f5d9ee7134d82b2..42ab2185084136f626b58162c84241edeb7c51c5 100644 (file)
@@ -167,6 +167,9 @@ func anyToSockaddrOS(rsa *RawSockaddrAny) (Sockaddr, error) {
 //sysnb        EpollCreate(size int) (fd int, err error)
 //epoll_create(size int) int
 
+//sysnb EpollCreate1(flags int) (fd int, err error)
+//epoll_create1(flags int) int
+
 //sysnb        EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error)
 //epoll_ctl(epfd int, op int, fd int, event *EpollEvent) int
 
index 07d3af3a622ac0038f96e8b0238fbcd2235a0f54..ba109f63ac1b23afe5e7f99e86ca102b70e7c7ca 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.
 
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
 
 package syscall
 
index e81e5c5845c3ae901c9b5e3b74326dda2df46494..4ce637082ca660d3441ab484b0d02359849b6310 100644 (file)
@@ -25,12 +25,12 @@ type InternalBenchmark struct {
 // B is a type passed to Benchmark functions to manage benchmark
 // timing and to specify the number of iterations to run.
 type B struct {
+       common
        N         int
        benchmark InternalBenchmark
-       ns        time.Duration
        bytes     int64
-       start     time.Time
        timerOn   bool
+       result    BenchmarkResult
 }
 
 // StartTimer starts timing a test.  This function is called automatically
@@ -48,7 +48,7 @@ func (b *B) StartTimer() {
 // want to measure.
 func (b *B) StopTimer() {
        if b.timerOn {
-               b.ns += time.Now().Sub(b.start)
+               b.duration += time.Now().Sub(b.start)
                b.timerOn = false
        }
 }
@@ -59,7 +59,7 @@ func (b *B) ResetTimer() {
        if b.timerOn {
                b.start = time.Now()
        }
-       b.ns = 0
+       b.duration = 0
 }
 
 // SetBytes records the number of bytes processed in a single operation.
@@ -70,7 +70,7 @@ func (b *B) nsPerOp() int64 {
        if b.N <= 0 {
                return 0
        }
-       return b.ns.Nanoseconds() / int64(b.N)
+       return b.duration.Nanoseconds() / int64(b.N)
 }
 
 // runN runs a single benchmark for the specified number of iterations.
@@ -127,17 +127,25 @@ func roundUp(n int) int {
        return 10 * base
 }
 
-// run times the benchmark function.  It gradually increases the number
+// run times the benchmark function in a separate goroutine.
+func (b *B) run() BenchmarkResult {
+       go b.launch()
+       <-b.signal
+       return b.result
+}
+
+// launch launches the benchmark function.  It gradually increases the number
 // of benchmark iterations until the benchmark runs for a second in order
 // to get a reasonable measurement.  It prints timing information in this form
 //             testing.BenchmarkHello  100000          19 ns/op
-func (b *B) run() BenchmarkResult {
+// launch is run by the fun function as a separate goroutine.
+func (b *B) launch() {
        // Run the benchmark for a single iteration in case it's expensive.
        n := 1
        b.runN(n)
        // Run the benchmark for at least the specified amount of time.
        d := time.Duration(*benchTime * float64(time.Second))
-       for b.ns < d && n < 1e9 {
+       for !b.failed && b.duration < d && n < 1e9 {
                last := n
                // Predict iterations/sec.
                if b.nsPerOp() == 0 {
@@ -153,7 +161,8 @@ func (b *B) run() BenchmarkResult {
                n = roundUp(n)
                b.runN(n)
        }
-       return BenchmarkResult{b.N, b.ns, b.bytes}
+       b.result = BenchmarkResult{b.N, b.duration, b.bytes}
+       b.signal <- b
 }
 
 // The results of a benchmark run.
@@ -215,14 +224,32 @@ func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks [
                }
                for _, procs := range cpuList {
                        runtime.GOMAXPROCS(procs)
-                       b := &B{benchmark: Benchmark}
+                       b := &B{
+                               common: common{
+                                       signal: make(chan interface{}),
+                               },
+                               benchmark: Benchmark,
+                       }
                        benchName := Benchmark.Name
                        if procs != 1 {
                                benchName = fmt.Sprintf("%s-%d", Benchmark.Name, procs)
                        }
                        fmt.Printf("%s\t", benchName)
                        r := b.run()
+                       if b.failed {
+                               // The output could be very long here, but probably isn't.
+                               // We print it all, regardless, because we don't want to trim the reason
+                               // the benchmark failed.
+                               fmt.Printf("--- FAIL: %s\n%s", benchName, b.output)
+                               continue
+                       }
                        fmt.Printf("%v\n", r)
+                       // Unlike with tests, we ignore the -chatty flag and always print output for
+                       // benchmarks since the output generation time will skew the results.
+                       if len(b.output) > 0 {
+                               b.trimOutput()
+                               fmt.Printf("--- BENCH: %s\n%s", benchName, b.output)
+                       }
                        if p := runtime.GOMAXPROCS(-1); p != procs {
                                fmt.Fprintf(os.Stderr, "testing: %s left GOMAXPROCS set to %d\n", benchName, p)
                        }
@@ -230,9 +257,31 @@ func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks [
        }
 }
 
+// trimOutput shortens the output from a benchmark, which can be very long.
+func (b *B) trimOutput() {
+       // The output is likely to appear multiple times because the benchmark
+       // is run multiple times, but at least it will be seen. This is not a big deal
+       // because benchmarks rarely print, but just in case, we trim it if it's too long.
+       const maxNewlines = 10
+       for nlCount, j := 0, 0; j < len(b.output); j++ {
+               if b.output[j] == '\n' {
+                       nlCount++
+                       if nlCount >= maxNewlines {
+                               b.output = append(b.output[:j], "\n\t... [output truncated]\n"...)
+                               break
+                       }
+               }
+       }
+}
+
 // Benchmark benchmarks a single function. Useful for creating
 // custom benchmarks that do not use gotest.
 func Benchmark(f func(b *B)) BenchmarkResult {
-       b := &B{benchmark: InternalBenchmark{"", f}}
+       b := &B{
+               common: common{
+                       signal: make(chan interface{}),
+               },
+               benchmark: InternalBenchmark{"", f},
+       }
        return b.run()
 }
index e23f13b6f16794b5d01c94d14c887a30d93b5201..fdeda137e7614facde2b4a4ade14e67970610ade 100644 (file)
@@ -9,6 +9,7 @@ import (
        "fmt"
        "io"
        "os"
+       "strings"
        "time"
 )
 
@@ -67,11 +68,9 @@ func RunExamples(examples []InternalExample) (ok bool) {
 
                // report any errors
                tstr := fmt.Sprintf("(%.2f seconds)", dt.Seconds())
-               if out != eg.Output {
-                       fmt.Printf(
-                               "--- FAIL: %s %s\ngot:\n%s\nwant:\n%s\n",
-                               eg.Name, tstr, out, eg.Output,
-                       )
+               if g, e := strings.TrimSpace(out), strings.TrimSpace(eg.Output); g != e {
+                       fmt.Printf("--- FAIL: %s %s\ngot:\n%s\nwant:\n%s\n",
+                               eg.Name, tstr, g, e)
                        ok = false
                } else if *chatty {
                        fmt.Printf("--- PASS: %s %s\n", eg.Name, tstr)
index ca2fced3fb9c168903f9678b9f9f220f0972e87f..16890e0b3fa2dc37fed36af4a2d411c5c7e572f7 100644 (file)
@@ -23,8 +23,8 @@
 //     }
 // The benchmark package will vary b.N until the benchmark function lasts
 // long enough to be timed reliably.  The output
-//     testing.BenchmarkHello  500000        4076 ns/op
-// means that the loop ran 500000 times at a speed of 4076 ns per loop.
+//     testing.BenchmarkHello    10000000    282 ns/op
+// means that the loop ran 10000000 times at a speed of 282 ns per loop.
 //
 // If a benchmark needs some expensive setup before running, the timer
 // may be stopped:
@@ -70,6 +70,17 @@ var (
        cpuList []int
 )
 
+// common holds the elements common between T and B and
+// captures common methods such as Errorf.
+type common struct {
+       output   []byte    // Output generated by test or benchmark.
+       failed   bool      // Test or benchmark has failed.
+       start    time.Time // Time test or benchmark started
+       duration time.Duration
+       self     interface{}      // To be sent on signal channel when done.
+       signal   chan interface{} // Output for serial tests.
+}
+
 // Short reports whether the -test.short flag is set.
 func Short() bool {
        return *short
@@ -79,7 +90,7 @@ func Short() bool {
 // If addFileLine is true, it also prefixes the string with the file and line of the call site.
 func decorate(s string, addFileLine bool) string {
        if addFileLine {
-               _, file, line, ok := runtime.Caller(3) // decorate + log + public function.
+               _, file, line, ok := runtime.Caller(4) // decorate + log + public function.
                if ok {
                        // Truncate file name at last file name separator.
                        if index := strings.LastIndex(file, "/"); index >= 0 {
@@ -111,70 +122,68 @@ func decorate(s string, addFileLine bool) string {
 // T is a type passed to Test functions to manage test state and support formatted test logs.
 // Logs are accumulated during execution and dumped to standard error when done.
 type T struct {
-       name          string        // Name of test.
-       errors        string        // Error string from test.
-       failed        bool          // Test has failed.
-       ch            chan *T       // Output for serial tests.
-       startParallel chan bool     // Parallel tests will wait on this.
-       start         time.Time     // Time test started
-       dt            time.Duration // Length of test
+       common
+       name          string    // Name of test.
+       startParallel chan bool // Parallel tests will wait on this.
 }
 
-// Fail marks the Test function as having failed but continues execution.
-func (t *T) Fail() { t.failed = true }
+// Fail marks the function as having failed but continues execution.
+func (c *common) Fail() { c.failed = true }
 
-// Failed returns whether the Test function has failed.
-func (t *T) Failed() bool { return t.failed }
+// Failed returns whether the function has failed.
+func (c *common) Failed() bool { return c.failed }
 
-// FailNow marks the Test function as having failed and stops its execution.
+// FailNow marks the function as having failed and stops its execution.
 // Execution will continue at the next Test.
-func (t *T) FailNow() {
-       t.dt = time.Now().Sub(t.start)
-       t.Fail()
-       t.ch <- t
+func (c *common) FailNow() {
+       c.duration = time.Now().Sub(c.start)
+       c.Fail()
+       c.signal <- c.self
        runtime.Goexit()
 }
 
 // log generates the output. It's always at the same stack depth.
-func (t *T) log(s string) { t.errors += decorate(s, true) }
+func (c *common) log(s string) {
+       c.output = append(c.output, decorate(s, true)...)
+}
 
-// Log formats its arguments using default formatting, analogous to Print(),
+// Log formats its arguments using default formatting, analogous to Println(),
 // and records the text in the error log.
-func (t *T) Log(args ...interface{}) { t.log(fmt.Sprintln(args...)) }
+func (c *common) Log(args ...interface{}) { c.log(fmt.Sprintln(args...)) }
 
 // Logf formats its arguments according to the format, analogous to Printf(),
 // and records the text in the error log.
-func (t *T) Logf(format string, args ...interface{}) { t.log(fmt.Sprintf(format, args...)) }
+func (c *common) Logf(format string, args ...interface{}) { c.log(fmt.Sprintf(format, args...)) }
 
 // Error is equivalent to Log() followed by Fail().
-func (t *T) Error(args ...interface{}) {
-       t.log(fmt.Sprintln(args...))
-       t.Fail()
+func (c *common) Error(args ...interface{}) {
+       c.log(fmt.Sprintln(args...))
+       c.Fail()
 }
 
 // Errorf is equivalent to Logf() followed by Fail().
-func (t *T) Errorf(format string, args ...interface{}) {
-       t.log(fmt.Sprintf(format, args...))
-       t.Fail()
+func (c *common) Errorf(format string, args ...interface{}) {
+       c.log(fmt.Sprintf(format, args...))
+       c.Fail()
 }
 
 // Fatal is equivalent to Log() followed by FailNow().
-func (t *T) Fatal(args ...interface{}) {
-       t.log(fmt.Sprintln(args...))
-       t.FailNow()
+func (c *common) Fatal(args ...interface{}) {
+       c.log(fmt.Sprintln(args...))
+       c.FailNow()
 }
 
 // Fatalf is equivalent to Logf() followed by FailNow().
-func (t *T) Fatalf(format string, args ...interface{}) {
-       t.log(fmt.Sprintf(format, args...))
-       t.FailNow()
+func (c *common) Fatalf(format string, args ...interface{}) {
+       c.log(fmt.Sprintf(format, args...))
+       c.FailNow()
 }
 
 // Parallel signals that this test is to be run in parallel with (and only with) 
 // other parallel tests in this CPU group.
 func (t *T) Parallel() {
-       t.ch <- nil       // Release main testing loop
-       <-t.startParallel // Wait for serial tests to finish
+       t.signal <- (*T)(nil) // Release main testing loop
+       <-t.startParallel     // Wait for serial tests to finish
 }
 
 // An internal type but exported because it is cross-package; part of the implementation
@@ -187,8 +196,8 @@ type InternalTest struct {
 func tRunner(t *T, test *InternalTest) {
        t.start = time.Now()
        test.F(t)
-       t.dt = time.Now().Sub(t.start)
-       t.ch <- t
+       t.duration = time.Now().Sub(t.start)
+       t.signal <- t
 }
 
 // An internal function but exported because it is cross-package; part of the implementation
@@ -211,13 +220,13 @@ func Main(matchString func(pat, str string) (bool, error), tests []InternalTest,
        after()
 }
 
-func report(t *T) {
-       tstr := fmt.Sprintf("(%.2f seconds)", t.dt.Seconds())
+func (t *T) report() {
+       tstr := fmt.Sprintf("(%.2f seconds)", t.duration.Seconds())
        format := "--- %s: %s %s\n%s"
        if t.failed {
-               fmt.Printf(format, "FAIL", t.name, tstr, t.errors)
+               fmt.Printf(format, "FAIL", t.name, tstr, t.output)
        } else if *chatty {
-               fmt.Printf(format, "PASS", t.name, tstr, t.errors)
+               fmt.Printf(format, "PASS", t.name, tstr, t.output)
        }
 }
 
@@ -227,9 +236,14 @@ func RunTests(matchString func(pat, str string) (bool, error), tests []InternalT
                fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
                return
        }
-       ch := make(chan *T)
        for _, procs := range cpuList {
                runtime.GOMAXPROCS(procs)
+               // We build a new channel tree for each run of the loop.
+               // collector merges in one channel all the upstream signals from parallel tests.
+               // If all tests pump to the same channel, a bug can occur where a test
+               // kicks off a goroutine that Fails, yet the test still delivers a completion signal,
+               // which skews the counting.
+               var collector = make(chan interface{})
 
                numParallel := 0
                startParallel := make(chan bool)
@@ -247,17 +261,27 @@ func RunTests(matchString func(pat, str string) (bool, error), tests []InternalT
                        if procs != 1 {
                                testName = fmt.Sprintf("%s-%d", tests[i].Name, procs)
                        }
-                       t := &T{ch: ch, name: testName, startParallel: startParallel}
+                       t := &T{
+                               common: common{
+                                       signal: make(chan interface{}),
+                               },
+                               name:          testName,
+                               startParallel: startParallel,
+                       }
+                       t.self = t
                        if *chatty {
                                fmt.Printf("=== RUN %s\n", t.name)
                        }
                        go tRunner(t, &tests[i])
-                       out := <-t.ch
+                       out := (<-t.signal).(*T)
                        if out == nil { // Parallel run.
+                               go func() {
+                                       collector <- <-t.signal
+                               }()
                                numParallel++
                                continue
                        }
-                       report(t)
+                       t.report()
                        ok = ok && !out.failed
                }
 
@@ -269,8 +293,8 @@ func RunTests(matchString func(pat, str string) (bool, error), tests []InternalT
                                numParallel--
                                continue
                        }
-                       t := <-ch
-                       report(t)
+                       t := (<-collector).(*T)
+                       t.report()
                        ok = ok && !t.failed
                        running--
                }
diff --git a/libgo/go/testing/wrapper.go b/libgo/go/testing/wrapper.go
new file mode 100644 (file)
index 0000000..2bef9df
--- /dev/null
@@ -0,0 +1,105 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains wrappers so t.Errorf etc. have documentation.
+// TODO: delete when godoc shows exported methods for unexported embedded fields.
+// TODO: need to change the argument to runtime.Caller in testing.go from 4 to 3 at that point.
+
+package testing
+
+// Fail marks the function as having failed but continues execution.
+func (b *B) Fail() {
+       b.common.Fail()
+}
+
+// Failed returns whether the function has failed.
+func (b *B) Failed() bool {
+       return b.common.Failed()
+}
+
+// FailNow marks the function as having failed and stops its execution.
+// Execution will continue at the next Test.
+func (b *B) FailNow() {
+       b.common.FailNow()
+}
+
+// Log formats its arguments using default formatting, analogous to Println(),
+// and records the text in the error log.
+func (b *B) Log(args ...interface{}) {
+       b.common.Log(args...)
+}
+
+// Logf formats its arguments according to the format, analogous to Printf(),
+// and records the text in the error log.
+func (b *B) Logf(format string, args ...interface{}) {
+       b.common.Logf(format, args...)
+}
+
+// Error is equivalent to Log() followed by Fail().
+func (b *B) Error(args ...interface{}) {
+       b.common.Error(args...)
+}
+
+// Errorf is equivalent to Logf() followed by Fail().
+func (b *B) Errorf(format string, args ...interface{}) {
+       b.common.Errorf(format, args...)
+}
+
+// Fatal is equivalent to Log() followed by FailNow().
+func (b *B) Fatal(args ...interface{}) {
+       b.common.Fatal(args...)
+}
+
+// Fatalf is equivalent to Logf() followed by FailNow().
+func (b *B) Fatalf(format string, args ...interface{}) {
+       b.common.Fatalf(format, args...)
+}
+
+// Fail marks the function as having failed but continues execution.
+func (t *T) Fail() {
+       t.common.Fail()
+}
+
+// Failed returns whether the function has failed.
+func (t *T) Failed() bool {
+       return t.common.Failed()
+}
+
+// FailNow marks the function as having failed and stops its execution.
+// Execution will continue at the next Test.
+func (t *T) FailNow() {
+       t.common.FailNow()
+}
+
+// Log formats its arguments using default formatting, analogous to Println(),
+// and records the text in the error log.
+func (t *T) Log(args ...interface{}) {
+       t.common.Log(args...)
+}
+
+// Logf formats its arguments according to the format, analogous to Printf(),
+// and records the text in the error log.
+func (t *T) Logf(format string, args ...interface{}) {
+       t.common.Logf(format, args...)
+}
+
+// Error is equivalent to Log() followed by Fail().
+func (t *T) Error(args ...interface{}) {
+       t.common.Error(args...)
+}
+
+// Errorf is equivalent to Logf() followed by Fail().
+func (t *T) Errorf(format string, args ...interface{}) {
+       t.common.Errorf(format, args...)
+}
+
+// Fatal is equivalent to Log() followed by FailNow().
+func (t *T) Fatal(args ...interface{}) {
+       t.common.Fatal(args...)
+}
+
+// Fatalf is equivalent to Logf() followed by FailNow().
+func (t *T) Fatalf(format string, args ...interface{}) {
+       t.common.Fatalf(format, args...)
+}
index b74bc3b01c90847363d7f19e6d1b6a518d8a2256..acb88afee3684afa1e1bfb4222277ac7664d2285 100644 (file)
@@ -107,7 +107,7 @@ func (t *Template) Execute(wr io.Writer, data interface{}) (err error) {
                vars: []variable{{"$", value}},
        }
        if t.Tree == nil || t.Root == nil {
-               state.errorf("must be parsed before execution")
+               state.errorf("%q is an incomplete or empty template", t.name)
        }
        state.walk(value, t.Root)
        return
@@ -497,7 +497,13 @@ func (s *state) evalCall(dot, fun reflect.Value, name string, args []parse.Node,
 // validateType guarantees that the value is valid and assignable to the type.
 func (s *state) validateType(value reflect.Value, typ reflect.Type) reflect.Value {
        if !value.IsValid() {
-               s.errorf("invalid value; expected %s", typ)
+               switch typ.Kind() {
+               case reflect.Interface, reflect.Ptr, reflect.Chan, reflect.Map, reflect.Slice, reflect.Func:
+                       // An untyped nil interface{}. Accept as a proper nil value.
+                       value = reflect.Zero(typ)
+               default:
+                       s.errorf("invalid value; expected %s", typ)
+               }
        }
        if !value.Type().AssignableTo(typ) {
                // Does one dereference or indirection work? We could do more, as we
index cf3c41572816f578b98a539db57b85e8bc975d4e..e33988b86c0930a1b60971c3ecbe596587f363af 100644 (file)
@@ -157,6 +157,10 @@ func (t *T) Method2(a uint16, b string) string {
        return fmt.Sprintf("Method2: %d %s", a, b)
 }
 
+func (t *T) Method3(v interface{}) string {
+       return fmt.Sprintf("Method3: %v", v)
+}
+
 func (t *T) MAdd(a int, b []int) []int {
        v := make([]int, len(b))
        for i, x := range b {
@@ -293,6 +297,7 @@ var execTests = []execTest{
        {".Method2(3, .X)", "-{{.Method2 3 .X}}-", "-Method2: 3 x-", tVal, true},
        {".Method2(.U16, `str`)", "-{{.Method2 .U16 `str`}}-", "-Method2: 16 str-", tVal, true},
        {".Method2(.U16, $x)", "{{if $x := .X}}-{{.Method2 .U16 $x}}{{end}}-", "-Method2: 16 x-", tVal, true},
+       {".Method3(nil)", "-{{.Method3 .MXI.unset}}-", "-Method3: <nil>-", tVal, true},
        {"method on var", "{{if $x := .}}-{{$x.Method2 .U16 $x.X}}{{end}}-", "-Method2: 16 x-", tVal, true},
        {"method on chained var",
                "{{range .MSIone}}{{if $.U.TrueFalse $.True}}{{$.U.TrueFalse $.True}}{{else}}WRONG{{end}}{{end}}",
@@ -322,6 +327,8 @@ var execTests = []execTest{
        {"if slice", "{{if .SI}}NON-EMPTY{{else}}EMPTY{{end}}", "NON-EMPTY", tVal, true},
        {"if emptymap", "{{if .MSIEmpty}}NON-EMPTY{{else}}EMPTY{{end}}", "EMPTY", tVal, true},
        {"if map", "{{if .MSI}}NON-EMPTY{{else}}EMPTY{{end}}", "NON-EMPTY", tVal, true},
+       {"if map unset", "{{if .MXI.none}}NON-ZERO{{else}}ZERO{{end}}", "ZERO", tVal, true},
+       {"if map not unset", "{{if not .MXI.none}}ZERO{{else}}NON-ZERO{{end}}", "ZERO", tVal, true},
        {"if $x with $y int", "{{if $x := true}}{{with $y := .I}}{{$x}},{{$y}}{{end}}{{end}}", "true,17", tVal, true},
        {"if $x with $x int", "{{if $x := true}}{{with $x := .I}}{{$x}},{{end}}{{$x}}{{end}}", "17,true", tVal, true},
 
index 55ae5f7da289b5854f639847de2c0612324c1842..56a7414e0ce875ddbb7d8c33771c3bd750c8f5bb 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.
 
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
 
 package time
 
index e58099676f07b02f500a729f3ce094b821fdefd5..33d557f7369b8ef792f4ddf99727bdfcca169310 100644 (file)
@@ -7,6 +7,8 @@
 // The calendrical calculations always assume a Gregorian calendar.
 package time
 
+import "errors"
+
 // A Time represents an instant in time with nanosecond precision.
 //
 // Programs using times should typically store and pass them as values,
@@ -564,6 +566,20 @@ func (t Time) Sub(u Time) Duration {
        return Duration(t.sec-u.sec)*Second + Duration(t.nsec-u.nsec)
 }
 
+// AddDate returns the time corresponding to adding the
+// given number of years, months, and days to t.
+// For example, AddDate(-1, 2, 3) applied to January 1, 2011
+// returns March 4, 2010.
+//
+// AddDate normalizes its result in the same way that Date does,
+// so, for example, adding one month to October 31 yields
+// December 1, the normalized form for November 31.
+func (t Time) AddDate(years int, months int, days int) Time {
+       year, month, day := t.Date()
+       hour, min, sec := t.Clock()
+       return Date(year+years, month+Month(months), day+days, hour, min, sec, int(t.nsec), t.loc)
+}
+
 const (
        secondsPerMinute = 60
        secondsPerHour   = 60 * 60
@@ -751,11 +767,11 @@ func (t Time) GobEncode() ([]byte, error) {
        } else {
                _, offset := t.Zone()
                if offset%60 != 0 {
-                       return nil, gobError("Time.GobEncode: zone offset has fractional minute")
+                       return nil, errors.New("Time.GobEncode: zone offset has fractional minute")
                }
                offset /= 60
                if offset < -32768 || offset == -1 || offset > 32767 {
-                       return nil, gobError("Time.GobEncode: unexpected zone offset")
+                       return nil, errors.New("Time.GobEncode: unexpected zone offset")
                }
                offsetMin = int16(offset)
        }
@@ -784,15 +800,15 @@ func (t Time) GobEncode() ([]byte, error) {
 // GobDecode implements the gob.GobDecoder interface.
 func (t *Time) GobDecode(buf []byte) error {
        if len(buf) == 0 {
-               return gobError("Time.GobDecode: no data")
+               return errors.New("Time.GobDecode: no data")
        }
 
        if buf[0] != timeGobVersion {
-               return gobError("Time.GobDecode: unsupported version")
+               return errors.New("Time.GobDecode: unsupported version")
        }
 
        if len(buf) != /*version*/ 1+ /*sec*/ 8+ /*nsec*/ 4+ /*zone offset*/ 2 {
-               return gobError("Time.GobDecode: invalid length")
+               return errors.New("Time.GobDecode: invalid length")
        }
 
        buf = buf[1:]
@@ -816,6 +832,52 @@ func (t *Time) GobDecode(buf []byte) error {
        return nil
 }
 
+// MarshalJSON implements the json.Marshaler interface.
+// Time is formatted as RFC3339.
+func (t Time) MarshalJSON() ([]byte, error) {
+       yearInt := t.Year()
+       if yearInt < 0 || yearInt > 9999 {
+               return nil, errors.New("Time.MarshalJSON: year outside of range [0,9999]")
+       }
+
+       // We need a four-digit year, but Format produces variable-width years.
+       year := itoa(yearInt)
+       year = "0000"[:4-len(year)] + year
+
+       var formattedTime string
+       if t.nsec == 0 {
+               // RFC3339, no fractional second
+               formattedTime = t.Format("-01-02T15:04:05Z07:00")
+       } else {
+               // RFC3339 with fractional second
+               formattedTime = t.Format("-01-02T15:04:05.000000000Z07:00")
+
+               // Trim trailing zeroes from fractional second.
+               const nanoEnd = 24 // Index of last digit of fractional second
+               var i int
+               for i = nanoEnd; formattedTime[i] == '0'; i-- {
+                       // Seek backwards until first significant digit is found.
+               }
+
+               formattedTime = formattedTime[:i+1] + formattedTime[nanoEnd+1:]
+       }
+
+       buf := make([]byte, 0, 1+len(year)+len(formattedTime)+1)
+       buf = append(buf, '"')
+       buf = append(buf, year...)
+       buf = append(buf, formattedTime...)
+       buf = append(buf, '"')
+       return buf, nil
+}
+
+// UnmarshalJSON implements the json.Unmarshaler interface.
+// Time is expected in RFC3339 format.
+func (t *Time) UnmarshalJSON(data []byte) (err error) {
+       *t, err = Parse("\""+RFC3339+"\"", string(data))
+       // Fractional seconds are handled implicitly by Parse.
+       return
+}
+
 // Unix returns the local Time corresponding to the given Unix time,
 // sec seconds and nsec nanoseconds since January 1, 1970 UTC.
 // It is valid to pass nsec outside the range [0, 999999999].
index 2a22e7b2746350ae861ca4152a30665d488a6cd4..484ae4266a31e3d0a190cdde724f327350c28f29 100644 (file)
@@ -7,6 +7,7 @@ package time_test
 import (
        "bytes"
        "encoding/gob"
+       "encoding/json"
        "strconv"
        "strings"
        "testing"
@@ -634,6 +635,32 @@ func TestDate(t *testing.T) {
        }
 }
 
+// Several ways of getting from
+// Fri Nov 18 7:56:35 PST 2011
+// to
+// Thu Mar 19 7:56:35 PST 2016
+var addDateTests = []struct {
+       years, months, days int
+}{
+       {4, 4, 1},
+       {3, 16, 1},
+       {3, 15, 30},
+       {5, -6, -18 - 30 - 12},
+}
+
+func TestAddDate(t *testing.T) {
+       t0 := Date(2011, 11, 18, 7, 56, 35, 0, UTC)
+       t1 := Date(2016, 3, 19, 7, 56, 35, 0, UTC)
+       for _, at := range addDateTests {
+               time := t0.AddDate(at.years, at.months, at.days)
+               if !time.Equal(t1) {
+                       t.Errorf("AddDate(%d, %d, %d) = %v, want %v",
+                               at.years, at.months, at.days,
+                               time, t1)
+               }
+       }
+}
+
 var daysInTests = []struct {
        year, month, di int
 }{
@@ -668,6 +695,12 @@ func TestAddToExactSecond(t *testing.T) {
        }
 }
 
+func equalTimeAndZone(a, b Time) bool {
+       aname, aoffset := a.Zone()
+       bname, boffset := b.Zone()
+       return a.Equal(b) && aoffset == boffset && aname == bname
+}
+
 var gobTests = []Time{
        Date(0, 1, 2, 3, 4, 5, 6, UTC),
        Date(7, 8, 9, 10, 11, 12, 13, FixedZone("", 0)),
@@ -687,12 +720,8 @@ func TestTimeGob(t *testing.T) {
                        t.Errorf("%v gob Encode error = %q, want nil", tt, err)
                } else if err := dec.Decode(&gobtt); err != nil {
                        t.Errorf("%v gob Decode error = %q, want nil", tt, err)
-               } else {
-                       gobname, goboffset := gobtt.Zone()
-                       name, offset := tt.Zone()
-                       if !gobtt.Equal(tt) || goboffset != offset || gobname != name {
-                               t.Errorf("Decoded time = %v, want %v", gobtt, tt)
-                       }
+               } else if !equalTimeAndZone(gobtt, tt) {
+                       t.Errorf("Decoded time = %v, want %v", gobtt, tt)
                }
                b.Reset()
        }
@@ -736,6 +765,57 @@ func TestNotGobEncodableTime(t *testing.T) {
        }
 }
 
+var jsonTests = []struct {
+       time Time
+       json string
+}{
+       {Date(9999, 4, 12, 23, 20, 50, .52*1e9, UTC), `"9999-04-12T23:20:50.52Z"`},
+       {Date(1996, 12, 19, 16, 39, 57, 0, Local), `"1996-12-19T16:39:57-08:00"`},
+       {Date(0, 1, 1, 0, 0, 0, 1, FixedZone("", 1*60)), `"0000-01-01T00:00:00.000000001+00:01"`},
+}
+
+func TestTimeJSON(t *testing.T) {
+       for _, tt := range jsonTests {
+               var jsonTime Time
+
+               if jsonBytes, err := json.Marshal(tt.time); err != nil {
+                       t.Errorf("%v json.Marshal error = %v, want nil", tt.time, err)
+               } else if string(jsonBytes) != tt.json {
+                       t.Errorf("%v JSON = %q, want %q", tt.time, string(jsonBytes), tt.json)
+               } else if err = json.Unmarshal(jsonBytes, &jsonTime); err != nil {
+                       t.Errorf("%v json.Unmarshal error = %v, want nil", tt.time, err)
+               } else if !equalTimeAndZone(jsonTime, tt.time) {
+                       t.Errorf("Unmarshaled time = %v, want %v", jsonTime, tt.time)
+               }
+       }
+}
+
+func TestInvalidTimeJSON(t *testing.T) {
+       var tt Time
+       err := json.Unmarshal([]byte(`{"now is the time":"buddy"}`), &tt)
+       _, isParseErr := err.(*ParseError)
+       if !isParseErr {
+               t.Errorf("expected *time.ParseError unmarshaling JSON, got %v", err)
+       }
+}
+
+var notJSONEncodableTimes = []struct {
+       time Time
+       want string
+}{
+       {Date(10000, 1, 1, 0, 0, 0, 0, UTC), "Time.MarshalJSON: year outside of range [0,9999]"},
+       {Date(-1, 1, 1, 0, 0, 0, 0, UTC), "Time.MarshalJSON: year outside of range [0,9999]"},
+}
+
+func TestNotJSONEncodableTime(t *testing.T) {
+       for _, tt := range notJSONEncodableTimes {
+               _, err := tt.time.MarshalJSON()
+               if err == nil || err.Error() != tt.want {
+                       t.Errorf("%v MarshalJSON error = %v, want %v", tt.time, err, tt.want)
+               }
+       }
+}
+
 func BenchmarkNow(b *testing.B) {
        for i := 0; i < b.N; i++ {
                Now()
index 83d5b983c6ec928bea451b346bc3d5652a8712c8..540b653c57d22e9977e38c291f3d29ca2c68a0d7 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.
 
-// +build darwin freebsd linux openbsd
+// +build darwin freebsd linux netbsd openbsd
 
 // Parse "zoneinfo" time zone file.
 // This is a fairly standard file format used on OS X, Linux, BSD, Sun, and others.
index 8320b032ead3abae7f65aad00fddfc725a770bfd..63f48e25693c6a30c58e59366c0485075125aa76 100644 (file)
@@ -74,7 +74,7 @@ A trivial example server:
                http.Handle("/echo", websocket.Handler(EchoServer));
                err := http.ListenAndServe(":12345", nil);
                if err != nil {
-                       panic("ListenAndServe: " + err.String())
+                       panic("ListenAndServe: " + err.Error())
                }
        }
 */
index 496abe53ad54eca290a4feb7cf9c9f730697c842..c8a57ca2816fa64d2f2cda722b837a1bebcc0396 100755 (executable)
@@ -168,8 +168,8 @@ for f in $runtime; do
   merge_c $f $f
 done
 
-merge_c linux/thread.c thread-linux.c
-merge_c linux/mem.c mem.c
+merge_c thread_linux.c thread-linux.c
+merge_c mem_linux.c mem.c
 
 (cd ${OLDDIR}/src/pkg && find . -name '*.go' -print) | while read f; do
   oldfile=${OLDDIR}/src/pkg/$f
index fe413fe42afb2621fbfaad6ac8b8e0490dd025ed..93031ffe253c605630d66604ee48a48bd619e60b 100644 (file)
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build ignore
+
 /*
  * Translate a .goc file into a .c file.  A .goc file is a combination
  * of a limited form of Go with C.
@@ -774,6 +776,7 @@ main(int argc, char **argv)
                }
        }
 
+       printf("// AUTO-GENERATED by autogen.sh; DO NOT EDIT\n\n");
        process_file();
        exit(0);
 }
index 4f3d507726d9e014eb4593e17b402c604e21967b..cdc12d7c75cd9d5002aa7263d91b2c8da8bffae3 100644 (file)
@@ -2,17 +2,19 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build freebsd linux
+
 #include "runtime.h"
 
 // This implementation depends on OS-specific implementations of
 //
-//     runtime.futexsleep(uint32 *addr, uint32 val, int64 ns)
+//     runtime_futexsleep(uint32 *addr, uint32 val, int64 ns)
 //             Atomically,
 //                     if(*addr == val) sleep
 //             Might be woken up spuriously; that's allowed.
 //             Don't sleep longer than ns; ns < 0 means forever.
 //
-//     runtime.futexwakeup(uint32 *addr, uint32 cnt)
+//     runtime_futexwakeup(uint32 *addr, uint32 cnt)
 //             If any procs are sleeping on addr, wake up at most cnt.
 
 enum
index 6b4fffbdcf82d67566e975f737b18aaec18a9f0d..b2a8f53be41e669f2b5643fbbe815a4677e5e2be 100644 (file)
@@ -2,21 +2,23 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build darwin netbsd openbsd plan9 windows
+
 #include "runtime.h"
 
 // This implementation depends on OS-specific implementations of
 //
-//     uintptr runtime.semacreate(void)
+//     uintptr runtime_semacreate(void)
 //             Create a semaphore, which will be assigned to m->waitsema.
 //             The zero value is treated as absence of any semaphore,
 //             so be sure to return a non-zero value.
 //
-//     int32 runtime.semasleep(int64 ns)
+//     int32 runtime_semasleep(int64 ns)
 //             If ns < 0, acquire m->waitsema and return 0.
 //             If ns >= 0, try to acquire m->waitsema for at most ns nanoseconds.
 //             Return 0 if the semaphore was acquired, -1 if interrupted or timed out.
 //
-//     int32 runtime.semawakeup(M *mp)
+//     int32 runtime_semawakeup(M *mp)
 //             Wake up mp, which is or will soon be sleeping on mp->waitsema.
 //
 
index f44f45083f7244410a177056ba1dcfb966133aa5..d143d19e5ba61247be12b200b169a65192a888ef 100644 (file)
@@ -12,8 +12,6 @@ package runtime
 #include "defs.h"
 #include "go-type.h"
 
-typedef struct __go_open_array Slice;
-
 // NOTE(rsc): Everything here could use cas if contention became an issue.
 static Lock proflock;
 
index 040a1b617c874d16580d22861c166207d95ecee0..94113b8db8397fd497e8dcecf94748d26f2f4086 100644 (file)
@@ -196,7 +196,7 @@ enum
 
 /* Macros.  */
 
-#ifdef __WINDOWS__
+#ifdef GOOS_windows
 enum {
    Windows = 1
 };
@@ -343,7 +343,6 @@ void        runtime_panic(Eface);
 #define runtime_printf printf
 #define runtime_malloc(s) __go_alloc(s)
 #define runtime_free(p) __go_free(p)
-#define runtime_memclr(buf, size) __builtin_memset((buf), 0, (size))
 #define runtime_strcmp(s1, s2) __builtin_strcmp((s1), (s2))
 #define runtime_mcmp(a, b, s) __builtin_memcmp((a), (b), (s))
 #define runtime_memmove(a, b, s) __builtin_memmove((a), (b), (s))
@@ -352,9 +351,6 @@ MCache*     runtime_allocmcache(void);
 void   free(void *v);
 struct __go_func_type;
 bool   runtime_addfinalizer(void*, void(*fn)(void*), const struct __go_func_type *);
-#define runtime_mmap mmap
-#define runtime_munmap munmap
-#define runtime_madvise madvise
 #define runtime_cas(pval, old, new) __sync_bool_compare_and_swap (pval, old, new)
 #define runtime_casp(pval, old, new) __sync_bool_compare_and_swap (pval, old, new)
 #define runtime_xadd(p, v) __sync_add_and_fetch (p, v)
@@ -384,6 +380,14 @@ void       runtime_osyield(void);
 void   runtime_LockOSThread(void) __asm__("libgo_runtime.runtime.LockOSThread");
 void   runtime_UnlockOSThread(void) __asm__("libgo_runtime.runtime.UnlockOSThread");
 
+/*
+ * low level C-called
+ */
+#define runtime_mmap mmap
+#define runtime_munmap munmap
+#define runtime_madvise madvise
+#define runtime_memclr(buf, size) __builtin_memset((buf), 0, (size))
+
 struct __go_func_type;
 void reflect_call(const struct __go_func_type *, const void *, _Bool, _Bool,
                  void **, void **)
index fbbe393bbeff0eb91bb2417ea0a04d495d61273a..486caf09a429244643697e229ef99d0ba24973f1 100644 (file)
@@ -4,6 +4,9 @@
 
 package runtime
 #include "runtime.h"
+#include "arch.h"
+#include "malloc.h"
+
 #define charntorune(pv, str, len) __go_get_rune(str, len, pv)
 
 int32