From af92e385667da3fc91ac7f9f0867a56c111110b8 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 25 Jan 2012 21:54:22 +0000 Subject: libgo: Update to weekly.2012-01-20. From-SVN: r183540 --- libgo/MERGE | 2 +- libgo/Makefile.am | 112 +-- libgo/Makefile.in | 296 ++++---- libgo/go/bytes/example_test.go | 4 + libgo/go/container/heap/heap.go | 8 +- libgo/go/crypto/ecdsa/ecdsa.go | 29 +- libgo/go/crypto/ecdsa/ecdsa_test.go | 4 +- libgo/go/crypto/elliptic/elliptic.go | 107 ++- libgo/go/crypto/elliptic/elliptic_test.go | 28 +- libgo/go/crypto/elliptic/p224.go | 685 +++++++++++++++++++ libgo/go/crypto/elliptic/p224_test.go | 47 ++ libgo/go/crypto/hmac/hmac.go | 44 +- libgo/go/crypto/hmac/hmac_test.go | 312 ++++++++- libgo/go/crypto/md4/md4.go | 5 + libgo/go/crypto/md5/md5.go | 5 + libgo/go/crypto/ocsp/ocsp_test.go | 4 + libgo/go/crypto/openpgp/canonical_text.go | 4 + libgo/go/crypto/openpgp/canonical_text_test.go | 4 + libgo/go/crypto/ripemd160/ripemd160.go | 2 + libgo/go/crypto/sha1/sha1.go | 5 + libgo/go/crypto/sha256/sha256.go | 5 + libgo/go/crypto/sha512/sha512.go | 5 + libgo/go/crypto/tls/cipher_suites.go | 2 +- libgo/go/crypto/tls/conn.go | 26 +- libgo/go/crypto/tls/key_agreement.go | 18 +- libgo/go/crypto/tls/root_unix.go | 9 +- libgo/go/crypto/x509/x509.go | 51 +- libgo/go/database/sql/convert.go | 133 ++++ libgo/go/database/sql/convert_test.go | 206 ++++++ libgo/go/database/sql/driver/driver.go | 207 ++++++ libgo/go/database/sql/driver/types.go | 265 +++++++ libgo/go/database/sql/driver/types_test.go | 61 ++ libgo/go/database/sql/fakedb_test.go | 598 ++++++++++++++++ libgo/go/database/sql/sql.go | 912 +++++++++++++++++++++++++ libgo/go/database/sql/sql_test.go | 404 +++++++++++ libgo/go/encoding/gob/debug.go | 4 + libgo/go/encoding/gob/dump.go | 4 + libgo/go/encoding/json/encode.go | 14 +- libgo/go/encoding/json/tagkey_test.go | 13 +- libgo/go/encoding/xml/marshal_test.go | 17 + libgo/go/encoding/xml/read.go | 4 + libgo/go/encoding/xml/typeinfo.go | 4 +- libgo/go/exp/gotype/testdata/test1.go | 4 + libgo/go/exp/inotify/inotify_linux_test.go | 9 +- libgo/go/exp/norm/trie_test.go | 4 + libgo/go/exp/proxy/proxy.go | 12 +- libgo/go/exp/sql/convert.go | 133 ---- libgo/go/exp/sql/convert_test.go | 173 ----- libgo/go/exp/sql/driver/driver.go | 207 ------ libgo/go/exp/sql/driver/types.go | 219 ------ libgo/go/exp/sql/driver/types_test.go | 61 -- libgo/go/exp/sql/fakedb_test.go | 597 ---------------- libgo/go/exp/sql/sql.go | 860 ----------------------- libgo/go/exp/sql/sql_test.go | 305 --------- libgo/go/exp/ssh/client.go | 5 +- libgo/go/exp/ssh/messages.go | 20 + libgo/go/exp/ssh/session.go | 8 +- libgo/go/exp/ssh/tcpip.go | 31 +- libgo/go/exp/ssh/transport.go | 36 +- libgo/go/exp/ssh/transport_test.go | 18 +- libgo/go/exp/types/check_test.go | 18 +- libgo/go/exp/types/gcimporter.go | 31 +- libgo/go/exp/utf8string/string.go | 203 ++++++ libgo/go/exp/utf8string/string_test.go | 123 ++++ libgo/go/fmt/fmt_test.go | 25 +- libgo/go/go/build/path.go | 4 +- libgo/go/go/build/pkgtest/sqrt_test.go | 4 + libgo/go/go/build/pkgtest/xsqrt_test.go | 4 + libgo/go/go/doc/comment.go | 18 +- libgo/go/go/doc/doc.go | 6 +- libgo/go/go/doc/doc_test.go | 194 +++--- libgo/go/go/doc/exports.go | 3 + libgo/go/go/doc/reader.go | 22 + libgo/go/go/doc/testdata/a.out | 13 + libgo/go/go/doc/testdata/a0.go | 8 + libgo/go/go/doc/testdata/a1.go | 8 + libgo/go/go/doc/testdata/b.go | 13 + libgo/go/go/doc/testdata/b.out | 34 + libgo/go/go/doc/testdata/benchmark.go | 293 ++++++++ libgo/go/go/doc/testdata/example.go | 81 +++ libgo/go/go/doc/testdata/template.txt | 65 ++ libgo/go/go/doc/testdata/testing.go | 404 +++++++++++ libgo/go/go/doc/testdata/testing.out | 156 +++++ libgo/go/go/parser/interface.go | 6 +- libgo/go/go/scanner/scanner.go | 2 +- libgo/go/go/token/position.go | 271 ++++---- libgo/go/go/token/position_test.go | 9 +- libgo/go/hash/adler32/adler32.go | 2 + libgo/go/hash/crc32/crc32.go | 2 + libgo/go/hash/crc64/crc64.go | 2 + libgo/go/hash/fnv/fnv.go | 5 + libgo/go/hash/hash.go | 6 + libgo/go/html/parse.go | 4 +- libgo/go/html/parse_test.go | 2 +- libgo/go/html/template/doc.go | 14 +- libgo/go/html/template/escape_test.go | 26 +- libgo/go/image/color/color.go | 63 +- libgo/go/image/color/ycbcr.go | 12 +- libgo/go/image/draw/draw.go | 52 +- libgo/go/image/geom.go | 2 +- libgo/go/image/image.go | 144 ++-- libgo/go/image/jpeg/reader.go | 15 +- libgo/go/image/tiff/reader.go | 12 +- libgo/go/image/ycbcr.go | 105 ++- libgo/go/image/ycbcr_test.go | 104 +++ libgo/go/io/ioutil/ioutil.go | 2 +- libgo/go/log/syslog/syslog_test.go | 3 +- libgo/go/math/rand/rand.go | 4 +- libgo/go/math/rand/rand_test.go | 10 +- libgo/go/mime/mediatype.go | 17 +- libgo/go/mime/mediatype_test.go | 21 + libgo/go/mime/type.go | 15 +- libgo/go/net/dnsclient_unix.go | 6 +- libgo/go/net/doc.go | 59 ++ libgo/go/net/fd.go | 55 +- libgo/go/net/fd_windows.go | 46 +- libgo/go/net/http/cgi/host.go | 2 +- libgo/go/net/http/cgi/host_test.go | 2 +- libgo/go/net/http/client.go | 19 +- libgo/go/net/http/client_test.go | 87 +++ libgo/go/net/http/doc.go | 3 +- libgo/go/net/http/fs_test.go | 12 +- libgo/go/net/http/httputil/dump.go | 25 +- libgo/go/net/http/httputil/reverseproxy.go | 5 - libgo/go/net/http/readrequest_test.go | 30 +- libgo/go/net/http/request.go | 22 +- libgo/go/net/http/requestwrite_test.go | 16 +- libgo/go/net/http/serve_test.go | 22 +- libgo/go/net/http/server.go | 15 +- libgo/go/net/http/transport.go | 7 +- libgo/go/net/ipraw_test.go | 3 +- libgo/go/net/iprawsock_plan9.go | 33 +- libgo/go/net/iprawsock_posix.go | 25 +- libgo/go/net/ipsock_plan9.go | 22 +- libgo/go/net/ipsock_posix.go | 4 +- libgo/go/net/lookup_plan9.go | 38 +- libgo/go/net/lookup_unix.go | 38 +- libgo/go/net/lookup_windows.go | 25 +- libgo/go/net/net.go | 65 +- libgo/go/net/pipe.go | 13 +- libgo/go/net/sendfile_linux.go | 9 - libgo/go/net/server_test.go | 9 +- libgo/go/net/smtp/auth.go | 3 +- libgo/go/net/sock.go | 14 +- libgo/go/net/sockopt.go | 15 +- libgo/go/net/sockopt_bsd.go | 5 +- libgo/go/net/sockopt_linux.go | 5 +- libgo/go/net/sockopt_windows.go | 2 +- libgo/go/net/tcpsock_plan9.go | 16 + libgo/go/net/tcpsock_posix.go | 26 +- libgo/go/net/timeout_test.go | 48 +- libgo/go/net/udpsock_plan9.go | 20 +- libgo/go/net/udpsock_posix.go | 23 +- libgo/go/net/unicast_test.go | 30 +- libgo/go/net/unixsock_plan9.go | 13 +- libgo/go/net/unixsock_posix.go | 60 +- libgo/go/net/url/url.go | 347 +++++----- libgo/go/net/url/url_test.go | 354 +++++----- libgo/go/old/netchan/common.go | 2 + libgo/go/old/regexp/regexp.go | 1 + libgo/go/os/dir.go | 14 +- libgo/go/os/dir_plan9.go | 31 +- libgo/go/os/dir_unix.go | 14 +- libgo/go/os/doc.go | 52 ++ libgo/go/os/error_plan9.go | 4 - libgo/go/os/error_posix.go | 4 - libgo/go/os/exec/lp_unix.go | 5 +- libgo/go/os/exec/lp_windows.go | 5 + libgo/go/os/exec_plan9.go | 5 +- libgo/go/os/exec_unix.go | 5 +- libgo/go/os/exec_windows.go | 5 +- libgo/go/os/file.go | 4 +- libgo/go/os/file_posix.go | 24 +- libgo/go/os/file_unix.go | 21 +- libgo/go/os/path.go | 2 +- libgo/go/os/stat_openbsd.go | 3 + libgo/go/os/sys_bsd.go | 2 +- libgo/go/os/sys_linux.go | 3 +- libgo/go/os/sys_plan9.go | 2 +- libgo/go/os/types.go | 5 +- libgo/go/patch/textdiff.go | 4 + libgo/go/path/example_test.go | 65 ++ libgo/go/reflect/all_test.go | 15 +- libgo/go/reflect/type.go | 2 +- libgo/go/regexp/all_test.go | 59 +- libgo/go/regexp/exec.go | 4 + libgo/go/regexp/regexp.go | 24 +- libgo/go/regexp/syntax/compile.go | 4 + libgo/go/regexp/syntax/prog.go | 4 + libgo/go/regexp/syntax/prog_test.go | 4 + libgo/go/regexp/syntax/regexp.go | 16 + libgo/go/runtime/extern.go | 2 +- libgo/go/runtime/gc_test.go | 4 + libgo/go/sync/atomic/atomic_test.go | 4 +- libgo/go/syscall/syscall.go | 8 + libgo/go/testing/example.go | 7 - libgo/go/testing/testing.go | 30 +- libgo/go/text/template/multi_test.go | 19 +- libgo/go/text/template/parse/node.go | 67 +- libgo/go/text/template/parse/parse_test.go | 56 +- libgo/go/text/template/template.go | 2 +- libgo/go/time/format.go | 4 + libgo/go/time/time.go | 32 +- libgo/go/unicode/utf8/string.go | 199 ------ libgo/go/unicode/utf8/string_test.go | 114 ---- libgo/go/websocket/hixie.go | 8 +- libgo/go/websocket/hybi.go | 4 +- libgo/go/websocket/websocket.go | 27 +- 208 files changed, 7952 insertions(+), 4780 deletions(-) create mode 100644 libgo/go/crypto/elliptic/p224.go create mode 100644 libgo/go/crypto/elliptic/p224_test.go create mode 100644 libgo/go/database/sql/convert.go create mode 100644 libgo/go/database/sql/convert_test.go create mode 100644 libgo/go/database/sql/driver/driver.go create mode 100644 libgo/go/database/sql/driver/types.go create mode 100644 libgo/go/database/sql/driver/types_test.go create mode 100644 libgo/go/database/sql/fakedb_test.go create mode 100644 libgo/go/database/sql/sql.go create mode 100644 libgo/go/database/sql/sql_test.go delete mode 100644 libgo/go/exp/sql/convert.go delete mode 100644 libgo/go/exp/sql/convert_test.go delete mode 100644 libgo/go/exp/sql/driver/driver.go delete mode 100644 libgo/go/exp/sql/driver/types.go delete mode 100644 libgo/go/exp/sql/driver/types_test.go delete mode 100644 libgo/go/exp/sql/fakedb_test.go delete mode 100644 libgo/go/exp/sql/sql.go delete mode 100644 libgo/go/exp/sql/sql_test.go create mode 100644 libgo/go/exp/utf8string/string.go create mode 100644 libgo/go/exp/utf8string/string_test.go create mode 100644 libgo/go/go/doc/testdata/a.out create mode 100644 libgo/go/go/doc/testdata/a0.go create mode 100644 libgo/go/go/doc/testdata/a1.go create mode 100644 libgo/go/go/doc/testdata/b.go create mode 100644 libgo/go/go/doc/testdata/b.out create mode 100644 libgo/go/go/doc/testdata/benchmark.go create mode 100644 libgo/go/go/doc/testdata/example.go create mode 100644 libgo/go/go/doc/testdata/template.txt create mode 100644 libgo/go/go/doc/testdata/testing.go create mode 100644 libgo/go/go/doc/testdata/testing.out create mode 100644 libgo/go/image/ycbcr_test.go create mode 100644 libgo/go/net/doc.go create mode 100644 libgo/go/os/doc.go create mode 100644 libgo/go/path/example_test.go delete mode 100644 libgo/go/unicode/utf8/string.go delete mode 100644 libgo/go/unicode/utf8/string_test.go diff --git a/libgo/MERGE b/libgo/MERGE index b72962f..4207948 100644 --- a/libgo/MERGE +++ b/libgo/MERGE @@ -1,4 +1,4 @@ -354b17404643 +9f2be4fbbf69 The first line of this file holds the Mercurial revision number of the last merge done from the master library sources. diff --git a/libgo/Makefile.am b/libgo/Makefile.am index 770a849..84b7019 100644 --- a/libgo/Makefile.am +++ b/libgo/Makefile.am @@ -197,6 +197,16 @@ toolexeclibgocryptox509dir = $(toolexeclibgocryptodir)/x509 toolexeclibgocryptox509_DATA = \ crypto/x509/pkix.gox +toolexeclibgodatabasedir = $(toolexeclibgodir)/database + +toolexeclibgodatabase_DATA = \ + database/sql.gox + +toolexeclibgodatabasesqldir = $(toolexeclibgodatabasedir)/sql + +toolexeclibgodatabasesql_DATA = \ + database/sql/driver.gox + toolexeclibgodebugdir = $(toolexeclibgodir)/debug toolexeclibgodebug_DATA = \ @@ -237,15 +247,10 @@ toolexeclibgoexp_DATA = \ exp/norm.gox \ exp/proxy.gox \ exp/spdy.gox \ - exp/sql.gox \ exp/ssh.gox \ exp/terminal.gox \ - exp/types.gox - -toolexeclibgoexpsqldir = $(toolexeclibgoexpdir)/sql - -toolexeclibgoexpsql_DATA = \ - exp/sql/driver.gox + exp/types.gox \ + exp/utf8string.gox toolexeclibgogodir = $(toolexeclibgodir)/go @@ -717,6 +722,7 @@ go_net_files = \ go/net/dnsclient_unix.go \ go/net/dnsconfig.go \ go/net/dnsmsg.go \ + go/net/doc.go \ $(go_net_newpollserver_file) \ go/net/fd.go \ $(go_net_fd_os_file) \ @@ -793,6 +799,7 @@ endif go_os_files = \ $(go_os_dir_file) \ go/os/dir.go \ + go/os/doc.go \ go/os/env.go \ go/os/error.go \ go/os/error_posix.go \ @@ -1005,7 +1012,8 @@ go_crypto_dsa_files = \ go_crypto_ecdsa_files = \ go/crypto/ecdsa/ecdsa.go go_crypto_elliptic_files = \ - go/crypto/elliptic/elliptic.go + go/crypto/elliptic/elliptic.go \ + go/crypto/elliptic/p224.go go_crypto_hmac_files = \ go/crypto/hmac/hmac.go go_crypto_md4_files = \ @@ -1094,6 +1102,14 @@ go_crypto_openpgp_s2k_files = \ go_crypto_x509_pkix_files = \ go/crypto/x509/pkix/pkix.go +go_database_sql_files = \ + go/database/sql/convert.go \ + go/database/sql/sql.go + +go_database_sql_driver_files = \ + go/database/sql/driver/driver.go \ + go/database/sql/driver/types.go + go_debug_dwarf_files = \ go/debug/dwarf/buf.go \ go/debug/dwarf/const.go \ @@ -1179,9 +1195,6 @@ go_exp_spdy_files = \ go/exp/spdy/read.go \ go/exp/spdy/types.go \ go/exp/spdy/write.go -go_exp_sql_files = \ - go/exp/sql/convert.go \ - go/exp/sql/sql.go go_exp_ssh_files = \ go/exp/ssh/channel.go \ go/exp/ssh/cipher.go \ @@ -1205,10 +1218,8 @@ go_exp_types_files = \ go/exp/types/gcimporter.go \ go/exp/types/types.go \ go/exp/types/universe.go - -go_exp_sql_driver_files = \ - go/exp/sql/driver/driver.go \ - go/exp/sql/driver/types.go +go_exp_utf8string_files = \ + go/exp/utf8string/string.go go_go_ast_files = \ go/go/ast/ast.go \ @@ -1467,7 +1478,6 @@ go_text_scanner_files = \ go_unicode_utf16_files = \ go/unicode/utf16/utf16.go go_unicode_utf8_files = \ - go/unicode/utf8/string.go \ go/unicode/utf8/utf8.go # Define Syscall and Syscall6. @@ -1751,6 +1761,8 @@ libgo_go_objs = \ crypto/openpgp/packet.lo \ crypto/openpgp/s2k.lo \ crypto/x509/pkix.lo \ + database/sql.lo \ + database/sql/driver.lo \ debug/dwarf.lo \ debug/elf.lo \ debug/gosym.lo \ @@ -1772,11 +1784,10 @@ libgo_go_objs = \ exp/norm.lo \ exp/proxy.lo \ exp/spdy.lo \ - exp/sql.lo \ exp/ssh.lo \ exp/terminal.lo \ exp/types.lo \ - exp/sql/driver.lo \ + exp/utf8string.lo \ html/template.lo \ go/ast.lo \ go/build.lo \ @@ -2646,6 +2657,26 @@ crypto/x509/pkix/check: $(CHECK_DEPS) @$(CHECK) .PHONY: crypto/x509/pkix/check +@go_include@ database/sql.lo.dep +database/sql.lo.dep: $(go_database_sql_files) + $(BUILDDEPS) +database/sql.lo: $(go_database_sql_files) + $(BUILDPACKAGE) +database/sql/check: $(CHECK_DEPS) + @$(MKDIR_P) database/sql + @$(CHECK) +.PHONY: database/sql/check + +@go_include@ database/sql/driver.lo.dep +database/sql/driver.lo.dep: $(go_database_sql_driver_files) + $(BUILDDEPS) +database/sql/driver.lo: $(go_database_sql_driver_files) + $(BUILDPACKAGE) +database/sql/driver/check: $(CHECK_DEPS) + @$(MKDIR_P) database/sql/driver + @$(CHECK) +.PHONY: database/sql/driver/check + @go_include@ debug/dwarf.lo.dep debug/dwarf.lo.dep: $(go_debug_dwarf_files) $(BUILDDEPS) @@ -2856,16 +2887,6 @@ exp/spdy/check: $(CHECK_DEPS) @$(CHECK) .PHONY: exp/spdy/check -@go_include@ exp/sql.lo.dep -exp/sql.lo.dep: $(go_exp_sql_files) - $(BUILDDEPS) -exp/sql.lo: $(go_exp_sql_files) - $(BUILDPACKAGE) -exp/sql/check: $(CHECK_DEPS) - @$(MKDIR_P) exp/sql - @$(CHECK) -.PHONY: exp/sql/check - @go_include@ exp/ssh.lo.dep exp/ssh.lo.dep: $(go_exp_ssh_files) $(BUILDDEPS) @@ -2896,6 +2917,16 @@ exp/types/check: $(CHECK_DEPS) @$(CHECK) .PHONY: exp/types/check +@go_include@ exp/utf8string.lo.dep +exp/utf8string.lo.dep: $(go_exp_utf8string_files) + $(BUILDDEPS) +exp/utf8string.lo: $(go_exp_utf8string_files) + $(BUILDPACKAGE) +exp/utf8string/check: $(CHECK_DEPS) + @$(MKDIR_P) exp/utf8string + @$(CHECK) +.PHONY: exp/utf8string/check + @go_include@ exp/inotify.lo.dep exp/inotify.lo.dep: $(go_exp_inotify_files) $(BUILDDEPS) @@ -2906,16 +2937,6 @@ exp/inotify/check: $(CHECK_DEPS) @$(CHECK) .PHONY: exp/inotify/check -@go_include@ exp/sql/driver.lo.dep -exp/sql/driver.lo.dep: $(go_exp_sql_driver_files) - $(BUILDDEPS) -exp/sql/driver.lo: $(go_exp_sql_driver_files) - $(BUILDPACKAGE) -exp/sql/driver/check: $(CHECK_DEPS) - @$(MKDIR_P) exp/sql/driver - @$(CHECK) -.PHONY: exp/sql/driver/check - @go_include@ html/template.lo.dep html/template.lo.dep: $(go_html_template_files) $(BUILDDEPS) @@ -3670,6 +3691,12 @@ crypto/openpgp/s2k.gox: crypto/openpgp/s2k.lo crypto/x509/pkix.gox: crypto/x509/pkix.lo $(BUILDGOX) +database/sql.gox: database/sql.lo + $(BUILDGOX) + +database/sql/driver.gox: database/sql/driver.lo + $(BUILDGOX) + debug/dwarf.gox: debug/dwarf.lo $(BUILDGOX) debug/elf.gox: debug/elf.lo @@ -3716,16 +3743,13 @@ exp/proxy.gox: exp/proxy.lo $(BUILDGOX) exp/spdy.gox: exp/spdy.lo $(BUILDGOX) -exp/sql.gox: exp/sql.lo - $(BUILDGOX) exp/ssh.gox: exp/ssh.lo $(BUILDGOX) exp/terminal.gox: exp/terminal.lo $(BUILDGOX) exp/types.gox: exp/types.lo $(BUILDGOX) - -exp/sql/driver.gox: exp/sql/driver.lo +exp/utf8string.gox: exp/utf8string.lo $(BUILDGOX) html/template.gox: html/template.lo @@ -3941,6 +3965,8 @@ TEST_PACKAGES = \ crypto/openpgp/elgamal/check \ crypto/openpgp/packet/check \ crypto/openpgp/s2k/check \ + database/sql/check \ + database/sql/driver/check \ debug/dwarf/check \ debug/elf/check \ debug/macho/check \ @@ -3962,9 +3988,9 @@ TEST_PACKAGES = \ exp/norm/check \ exp/proxy/check \ exp/spdy/check \ - exp/sql/check \ exp/ssh/check \ exp/terminal/check \ + exp/utf8string/check \ html/template/check \ go/ast/check \ $(go_build_check_omitted_since_it_calls_6g) \ diff --git a/libgo/Makefile.in b/libgo/Makefile.in index b82bf42..31c58d9 100644 --- a/libgo/Makefile.in +++ b/libgo/Makefile.in @@ -99,10 +99,11 @@ am__installdirs = "$(DESTDIR)$(toolexeclibdir)" \ "$(DESTDIR)$(toolexeclibgocryptodir)" \ "$(DESTDIR)$(toolexeclibgocryptoopenpgpdir)" \ "$(DESTDIR)$(toolexeclibgocryptox509dir)" \ + "$(DESTDIR)$(toolexeclibgodatabasedir)" \ + "$(DESTDIR)$(toolexeclibgodatabasesqldir)" \ "$(DESTDIR)$(toolexeclibgodebugdir)" \ "$(DESTDIR)$(toolexeclibgoencodingdir)" \ "$(DESTDIR)$(toolexeclibgoexpdir)" \ - "$(DESTDIR)$(toolexeclibgoexpsqldir)" \ "$(DESTDIR)$(toolexeclibgogodir)" \ "$(DESTDIR)$(toolexeclibgohashdir)" \ "$(DESTDIR)$(toolexeclibgohtmldir)" \ @@ -154,33 +155,33 @@ am__DEPENDENCIES_2 = bufio/bufio.lo bytes/bytes.lo bytes/index.lo \ crypto/tls.lo crypto/twofish.lo crypto/x509.lo crypto/xtea.lo \ crypto/openpgp/armor.lo crypto/openpgp/elgamal.lo \ crypto/openpgp/errors.lo crypto/openpgp/packet.lo \ - crypto/openpgp/s2k.lo crypto/x509/pkix.lo debug/dwarf.lo \ - debug/elf.lo debug/gosym.lo debug/macho.lo debug/pe.lo \ - encoding/ascii85.lo encoding/asn1.lo encoding/base32.lo \ - encoding/base64.lo encoding/binary.lo encoding/csv.lo \ - encoding/git85.lo encoding/gob.lo encoding/hex.lo \ - encoding/json.lo encoding/pem.lo encoding/xml.lo exp/ebnf.lo \ - exp/norm.lo exp/proxy.lo exp/spdy.lo exp/sql.lo exp/ssh.lo \ - exp/terminal.lo exp/types.lo exp/sql/driver.lo \ - html/template.lo go/ast.lo go/build.lo go/doc.lo go/parser.lo \ - go/printer.lo go/scanner.lo go/token.lo hash/adler32.lo \ - hash/crc32.lo hash/crc64.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 \ - 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 + crypto/openpgp/s2k.lo crypto/x509/pkix.lo database/sql.lo \ + database/sql/driver.lo debug/dwarf.lo debug/elf.lo \ + debug/gosym.lo debug/macho.lo debug/pe.lo encoding/ascii85.lo \ + encoding/asn1.lo encoding/base32.lo encoding/base64.lo \ + encoding/binary.lo encoding/csv.lo encoding/git85.lo \ + encoding/gob.lo encoding/hex.lo encoding/json.lo \ + encoding/pem.lo encoding/xml.lo exp/ebnf.lo exp/norm.lo \ + exp/proxy.lo exp/spdy.lo exp/ssh.lo exp/terminal.lo \ + exp/types.lo exp/utf8string.lo html/template.lo go/ast.lo \ + go/build.lo go/doc.lo go/parser.lo go/printer.lo go/scanner.lo \ + go/token.lo hash/adler32.lo hash/crc32.lo hash/crc64.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 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) @@ -289,20 +290,20 @@ RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ DATA = $(toolexeclibgo_DATA) $(toolexeclibgoarchive_DATA) \ $(toolexeclibgocompress_DATA) $(toolexeclibgocontainer_DATA) \ $(toolexeclibgocrypto_DATA) $(toolexeclibgocryptoopenpgp_DATA) \ - $(toolexeclibgocryptox509_DATA) $(toolexeclibgodebug_DATA) \ + $(toolexeclibgocryptox509_DATA) $(toolexeclibgodatabase_DATA) \ + $(toolexeclibgodatabasesql_DATA) $(toolexeclibgodebug_DATA) \ $(toolexeclibgoencoding_DATA) $(toolexeclibgoexp_DATA) \ - $(toolexeclibgoexpsql_DATA) $(toolexeclibgogo_DATA) \ - $(toolexeclibgohash_DATA) $(toolexeclibgohtml_DATA) \ - $(toolexeclibgoimage_DATA) $(toolexeclibgoindex_DATA) \ - $(toolexeclibgoio_DATA) $(toolexeclibgolog_DATA) \ - $(toolexeclibgomath_DATA) $(toolexeclibgomime_DATA) \ - $(toolexeclibgonet_DATA) $(toolexeclibgonethttp_DATA) \ - $(toolexeclibgonetrpc_DATA) $(toolexeclibgoold_DATA) \ - $(toolexeclibgoos_DATA) $(toolexeclibgopath_DATA) \ - $(toolexeclibgoregexp_DATA) $(toolexeclibgoruntime_DATA) \ - $(toolexeclibgosync_DATA) $(toolexeclibgotesting_DATA) \ - $(toolexeclibgotext_DATA) $(toolexeclibgotexttemplate_DATA) \ - $(toolexeclibgounicode_DATA) + $(toolexeclibgogo_DATA) $(toolexeclibgohash_DATA) \ + $(toolexeclibgohtml_DATA) $(toolexeclibgoimage_DATA) \ + $(toolexeclibgoindex_DATA) $(toolexeclibgoio_DATA) \ + $(toolexeclibgolog_DATA) $(toolexeclibgomath_DATA) \ + $(toolexeclibgomime_DATA) $(toolexeclibgonet_DATA) \ + $(toolexeclibgonethttp_DATA) $(toolexeclibgonetrpc_DATA) \ + $(toolexeclibgoold_DATA) $(toolexeclibgoos_DATA) \ + $(toolexeclibgopath_DATA) $(toolexeclibgoregexp_DATA) \ + $(toolexeclibgoruntime_DATA) $(toolexeclibgosync_DATA) \ + $(toolexeclibgotesting_DATA) $(toolexeclibgotext_DATA) \ + $(toolexeclibgotexttemplate_DATA) $(toolexeclibgounicode_DATA) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ @@ -661,6 +662,14 @@ toolexeclibgocryptox509dir = $(toolexeclibgocryptodir)/x509 toolexeclibgocryptox509_DATA = \ crypto/x509/pkix.gox +toolexeclibgodatabasedir = $(toolexeclibgodir)/database +toolexeclibgodatabase_DATA = \ + database/sql.gox + +toolexeclibgodatabasesqldir = $(toolexeclibgodatabasedir)/sql +toolexeclibgodatabasesql_DATA = \ + database/sql/driver.gox + toolexeclibgodebugdir = $(toolexeclibgodir)/debug toolexeclibgodebug_DATA = \ debug/dwarf.gox \ @@ -695,14 +704,10 @@ toolexeclibgoexp_DATA = \ exp/norm.gox \ exp/proxy.gox \ exp/spdy.gox \ - exp/sql.gox \ exp/ssh.gox \ exp/terminal.gox \ - exp/types.gox - -toolexeclibgoexpsqldir = $(toolexeclibgoexpdir)/sql -toolexeclibgoexpsql_DATA = \ - exp/sql/driver.gox + exp/types.gox \ + exp/utf8string.gox toolexeclibgogodir = $(toolexeclibgodir)/go toolexeclibgogo_DATA = \ @@ -1072,6 +1077,7 @@ go_net_files = \ go/net/dnsclient_unix.go \ go/net/dnsconfig.go \ go/net/dnsmsg.go \ + go/net/doc.go \ $(go_net_newpollserver_file) \ go/net/fd.go \ $(go_net_fd_os_file) \ @@ -1118,6 +1124,7 @@ go_net_files = \ go_os_files = \ $(go_os_dir_file) \ go/os/dir.go \ + go/os/doc.go \ go/os/env.go \ go/os/error.go \ go/os/error_posix.go \ @@ -1320,7 +1327,8 @@ go_crypto_ecdsa_files = \ go/crypto/ecdsa/ecdsa.go go_crypto_elliptic_files = \ - go/crypto/elliptic/elliptic.go + go/crypto/elliptic/elliptic.go \ + go/crypto/elliptic/p224.go go_crypto_hmac_files = \ go/crypto/hmac/hmac.go @@ -1430,6 +1438,14 @@ go_crypto_openpgp_s2k_files = \ go_crypto_x509_pkix_files = \ go/crypto/x509/pkix/pkix.go +go_database_sql_files = \ + go/database/sql/convert.go \ + go/database/sql/sql.go + +go_database_sql_driver_files = \ + go/database/sql/driver/driver.go \ + go/database/sql/driver/types.go + go_debug_dwarf_files = \ go/debug/dwarf/buf.go \ go/debug/dwarf/const.go \ @@ -1535,10 +1551,6 @@ go_exp_spdy_files = \ go/exp/spdy/types.go \ go/exp/spdy/write.go -go_exp_sql_files = \ - go/exp/sql/convert.go \ - go/exp/sql/sql.go - go_exp_ssh_files = \ go/exp/ssh/channel.go \ go/exp/ssh/cipher.go \ @@ -1565,9 +1577,8 @@ go_exp_types_files = \ go/exp/types/types.go \ go/exp/types/universe.go -go_exp_sql_driver_files = \ - go/exp/sql/driver/driver.go \ - go/exp/sql/driver/types.go +go_exp_utf8string_files = \ + go/exp/utf8string/string.go go_go_ast_files = \ go/go/ast/ast.go \ @@ -1854,7 +1865,6 @@ go_unicode_utf16_files = \ go/unicode/utf16/utf16.go go_unicode_utf8_files = \ - go/unicode/utf8/string.go \ go/unicode/utf8/utf8.go @LIBGO_IS_RTEMS_FALSE@syscall_syscall_file = go/syscall/syscall_unix.go @@ -2025,6 +2035,8 @@ libgo_go_objs = \ crypto/openpgp/packet.lo \ crypto/openpgp/s2k.lo \ crypto/x509/pkix.lo \ + database/sql.lo \ + database/sql/driver.lo \ debug/dwarf.lo \ debug/elf.lo \ debug/gosym.lo \ @@ -2046,11 +2058,10 @@ libgo_go_objs = \ exp/norm.lo \ exp/proxy.lo \ exp/spdy.lo \ - exp/sql.lo \ exp/ssh.lo \ exp/terminal.lo \ exp/types.lo \ - exp/sql/driver.lo \ + exp/utf8string.lo \ html/template.lo \ go/ast.lo \ go/build.lo \ @@ -2294,6 +2305,8 @@ TEST_PACKAGES = \ crypto/openpgp/elgamal/check \ crypto/openpgp/packet/check \ crypto/openpgp/s2k/check \ + database/sql/check \ + database/sql/driver/check \ debug/dwarf/check \ debug/elf/check \ debug/macho/check \ @@ -2315,9 +2328,9 @@ TEST_PACKAGES = \ exp/norm/check \ exp/proxy/check \ exp/spdy/check \ - exp/sql/check \ exp/ssh/check \ exp/terminal/check \ + exp/utf8string/check \ html/template/check \ go/ast/check \ $(go_build_check_omitted_since_it_calls_6g) \ @@ -3365,6 +3378,46 @@ uninstall-toolexeclibgocryptox509DATA: test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(toolexeclibgocryptox509dir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(toolexeclibgocryptox509dir)" && rm -f $$files +install-toolexeclibgodatabaseDATA: $(toolexeclibgodatabase_DATA) + @$(NORMAL_INSTALL) + test -z "$(toolexeclibgodatabasedir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgodatabasedir)" + @list='$(toolexeclibgodatabase_DATA)'; test -n "$(toolexeclibgodatabasedir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(toolexeclibgodatabasedir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgodatabasedir)" || exit $$?; \ + done + +uninstall-toolexeclibgodatabaseDATA: + @$(NORMAL_UNINSTALL) + @list='$(toolexeclibgodatabase_DATA)'; test -n "$(toolexeclibgodatabasedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(toolexeclibgodatabasedir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(toolexeclibgodatabasedir)" && rm -f $$files +install-toolexeclibgodatabasesqlDATA: $(toolexeclibgodatabasesql_DATA) + @$(NORMAL_INSTALL) + test -z "$(toolexeclibgodatabasesqldir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgodatabasesqldir)" + @list='$(toolexeclibgodatabasesql_DATA)'; test -n "$(toolexeclibgodatabasesqldir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(toolexeclibgodatabasesqldir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgodatabasesqldir)" || exit $$?; \ + done + +uninstall-toolexeclibgodatabasesqlDATA: + @$(NORMAL_UNINSTALL) + @list='$(toolexeclibgodatabasesql_DATA)'; test -n "$(toolexeclibgodatabasesqldir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(toolexeclibgodatabasesqldir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(toolexeclibgodatabasesqldir)" && rm -f $$files install-toolexeclibgodebugDATA: $(toolexeclibgodebug_DATA) @$(NORMAL_INSTALL) test -z "$(toolexeclibgodebugdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgodebugdir)" @@ -3425,26 +3478,6 @@ uninstall-toolexeclibgoexpDATA: test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(toolexeclibgoexpdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(toolexeclibgoexpdir)" && rm -f $$files -install-toolexeclibgoexpsqlDATA: $(toolexeclibgoexpsql_DATA) - @$(NORMAL_INSTALL) - test -z "$(toolexeclibgoexpsqldir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgoexpsqldir)" - @list='$(toolexeclibgoexpsql_DATA)'; test -n "$(toolexeclibgoexpsqldir)" || list=; \ - for p in $$list; do \ - if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ - echo "$$d$$p"; \ - done | $(am__base_list) | \ - while read files; do \ - echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(toolexeclibgoexpsqldir)'"; \ - $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgoexpsqldir)" || exit $$?; \ - done - -uninstall-toolexeclibgoexpsqlDATA: - @$(NORMAL_UNINSTALL) - @list='$(toolexeclibgoexpsql_DATA)'; test -n "$(toolexeclibgoexpsqldir)" || list=; \ - files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ - test -n "$$files" || exit 0; \ - echo " ( cd '$(DESTDIR)$(toolexeclibgoexpsqldir)' && rm -f" $$files ")"; \ - cd "$(DESTDIR)$(toolexeclibgoexpsqldir)" && rm -f $$files install-toolexeclibgogoDATA: $(toolexeclibgogo_DATA) @$(NORMAL_INSTALL) test -z "$(toolexeclibgogodir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgogodir)" @@ -4202,7 +4235,7 @@ all-am: Makefile $(LIBRARIES) $(LTLIBRARIES) all-multi $(DATA) \ config.h installdirs: installdirs-recursive installdirs-am: - for dir in "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibgodir)" "$(DESTDIR)$(toolexeclibgoarchivedir)" "$(DESTDIR)$(toolexeclibgocompressdir)" "$(DESTDIR)$(toolexeclibgocontainerdir)" "$(DESTDIR)$(toolexeclibgocryptodir)" "$(DESTDIR)$(toolexeclibgocryptoopenpgpdir)" "$(DESTDIR)$(toolexeclibgocryptox509dir)" "$(DESTDIR)$(toolexeclibgodebugdir)" "$(DESTDIR)$(toolexeclibgoencodingdir)" "$(DESTDIR)$(toolexeclibgoexpdir)" "$(DESTDIR)$(toolexeclibgoexpsqldir)" "$(DESTDIR)$(toolexeclibgogodir)" "$(DESTDIR)$(toolexeclibgohashdir)" "$(DESTDIR)$(toolexeclibgohtmldir)" "$(DESTDIR)$(toolexeclibgoimagedir)" "$(DESTDIR)$(toolexeclibgoindexdir)" "$(DESTDIR)$(toolexeclibgoiodir)" "$(DESTDIR)$(toolexeclibgologdir)" "$(DESTDIR)$(toolexeclibgomathdir)" "$(DESTDIR)$(toolexeclibgomimedir)" "$(DESTDIR)$(toolexeclibgonetdir)" "$(DESTDIR)$(toolexeclibgonethttpdir)" "$(DESTDIR)$(toolexeclibgonetrpcdir)" "$(DESTDIR)$(toolexeclibgoolddir)" "$(DESTDIR)$(toolexeclibgoosdir)" "$(DESTDIR)$(toolexeclibgopathdir)" "$(DESTDIR)$(toolexeclibgoregexpdir)" "$(DESTDIR)$(toolexeclibgoruntimedir)" "$(DESTDIR)$(toolexeclibgosyncdir)" "$(DESTDIR)$(toolexeclibgotestingdir)" "$(DESTDIR)$(toolexeclibgotextdir)" "$(DESTDIR)$(toolexeclibgotexttemplatedir)" "$(DESTDIR)$(toolexeclibgounicodedir)"; do \ + for dir in "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibgodir)" "$(DESTDIR)$(toolexeclibgoarchivedir)" "$(DESTDIR)$(toolexeclibgocompressdir)" "$(DESTDIR)$(toolexeclibgocontainerdir)" "$(DESTDIR)$(toolexeclibgocryptodir)" "$(DESTDIR)$(toolexeclibgocryptoopenpgpdir)" "$(DESTDIR)$(toolexeclibgocryptox509dir)" "$(DESTDIR)$(toolexeclibgodatabasedir)" "$(DESTDIR)$(toolexeclibgodatabasesqldir)" "$(DESTDIR)$(toolexeclibgodebugdir)" "$(DESTDIR)$(toolexeclibgoencodingdir)" "$(DESTDIR)$(toolexeclibgoexpdir)" "$(DESTDIR)$(toolexeclibgogodir)" "$(DESTDIR)$(toolexeclibgohashdir)" "$(DESTDIR)$(toolexeclibgohtmldir)" "$(DESTDIR)$(toolexeclibgoimagedir)" "$(DESTDIR)$(toolexeclibgoindexdir)" "$(DESTDIR)$(toolexeclibgoiodir)" "$(DESTDIR)$(toolexeclibgologdir)" "$(DESTDIR)$(toolexeclibgomathdir)" "$(DESTDIR)$(toolexeclibgomimedir)" "$(DESTDIR)$(toolexeclibgonetdir)" "$(DESTDIR)$(toolexeclibgonethttpdir)" "$(DESTDIR)$(toolexeclibgonetrpcdir)" "$(DESTDIR)$(toolexeclibgoolddir)" "$(DESTDIR)$(toolexeclibgoosdir)" "$(DESTDIR)$(toolexeclibgopathdir)" "$(DESTDIR)$(toolexeclibgoregexpdir)" "$(DESTDIR)$(toolexeclibgoruntimedir)" "$(DESTDIR)$(toolexeclibgosyncdir)" "$(DESTDIR)$(toolexeclibgotestingdir)" "$(DESTDIR)$(toolexeclibgotextdir)" "$(DESTDIR)$(toolexeclibgotexttemplatedir)" "$(DESTDIR)$(toolexeclibgounicodedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive @@ -4270,14 +4303,16 @@ install-exec-am: install-multi install-toolexeclibLIBRARIES \ install-toolexeclibgocryptoDATA \ install-toolexeclibgocryptoopenpgpDATA \ install-toolexeclibgocryptox509DATA \ + install-toolexeclibgodatabaseDATA \ + install-toolexeclibgodatabasesqlDATA \ install-toolexeclibgodebugDATA \ install-toolexeclibgoencodingDATA install-toolexeclibgoexpDATA \ - install-toolexeclibgoexpsqlDATA install-toolexeclibgogoDATA \ - install-toolexeclibgohashDATA install-toolexeclibgohtmlDATA \ - install-toolexeclibgoimageDATA install-toolexeclibgoindexDATA \ - install-toolexeclibgoioDATA install-toolexeclibgologDATA \ - install-toolexeclibgomathDATA install-toolexeclibgomimeDATA \ - install-toolexeclibgonetDATA install-toolexeclibgonethttpDATA \ + install-toolexeclibgogoDATA install-toolexeclibgohashDATA \ + install-toolexeclibgohtmlDATA install-toolexeclibgoimageDATA \ + install-toolexeclibgoindexDATA install-toolexeclibgoioDATA \ + install-toolexeclibgologDATA install-toolexeclibgomathDATA \ + install-toolexeclibgomimeDATA install-toolexeclibgonetDATA \ + install-toolexeclibgonethttpDATA \ install-toolexeclibgonetrpcDATA install-toolexeclibgooldDATA \ install-toolexeclibgoosDATA install-toolexeclibgopathDATA \ install-toolexeclibgoregexpDATA \ @@ -4334,11 +4369,12 @@ uninstall-am: uninstall-toolexeclibLIBRARIES \ uninstall-toolexeclibgocryptoDATA \ uninstall-toolexeclibgocryptoopenpgpDATA \ uninstall-toolexeclibgocryptox509DATA \ + uninstall-toolexeclibgodatabaseDATA \ + uninstall-toolexeclibgodatabasesqlDATA \ uninstall-toolexeclibgodebugDATA \ uninstall-toolexeclibgoencodingDATA \ - uninstall-toolexeclibgoexpDATA \ - uninstall-toolexeclibgoexpsqlDATA \ - uninstall-toolexeclibgogoDATA uninstall-toolexeclibgohashDATA \ + uninstall-toolexeclibgoexpDATA uninstall-toolexeclibgogoDATA \ + uninstall-toolexeclibgohashDATA \ uninstall-toolexeclibgohtmlDATA \ uninstall-toolexeclibgoimageDATA \ uninstall-toolexeclibgoindexDATA uninstall-toolexeclibgoioDATA \ @@ -4382,14 +4418,16 @@ uninstall-am: uninstall-toolexeclibLIBRARIES \ install-toolexeclibgocryptoDATA \ install-toolexeclibgocryptoopenpgpDATA \ install-toolexeclibgocryptox509DATA \ + install-toolexeclibgodatabaseDATA \ + install-toolexeclibgodatabasesqlDATA \ install-toolexeclibgodebugDATA \ install-toolexeclibgoencodingDATA install-toolexeclibgoexpDATA \ - install-toolexeclibgoexpsqlDATA install-toolexeclibgogoDATA \ - install-toolexeclibgohashDATA install-toolexeclibgohtmlDATA \ - install-toolexeclibgoimageDATA install-toolexeclibgoindexDATA \ - install-toolexeclibgoioDATA install-toolexeclibgologDATA \ - install-toolexeclibgomathDATA install-toolexeclibgomimeDATA \ - install-toolexeclibgonetDATA install-toolexeclibgonethttpDATA \ + install-toolexeclibgogoDATA install-toolexeclibgohashDATA \ + install-toolexeclibgohtmlDATA install-toolexeclibgoimageDATA \ + install-toolexeclibgoindexDATA install-toolexeclibgoioDATA \ + install-toolexeclibgologDATA install-toolexeclibgomathDATA \ + install-toolexeclibgomimeDATA install-toolexeclibgonetDATA \ + install-toolexeclibgonethttpDATA \ install-toolexeclibgonetrpcDATA install-toolexeclibgooldDATA \ install-toolexeclibgoosDATA install-toolexeclibgopathDATA \ install-toolexeclibgoregexpDATA \ @@ -4410,11 +4448,12 @@ uninstall-am: uninstall-toolexeclibLIBRARIES \ uninstall-toolexeclibgocryptoDATA \ uninstall-toolexeclibgocryptoopenpgpDATA \ uninstall-toolexeclibgocryptox509DATA \ + uninstall-toolexeclibgodatabaseDATA \ + uninstall-toolexeclibgodatabasesqlDATA \ uninstall-toolexeclibgodebugDATA \ uninstall-toolexeclibgoencodingDATA \ - uninstall-toolexeclibgoexpDATA \ - uninstall-toolexeclibgoexpsqlDATA \ - uninstall-toolexeclibgogoDATA uninstall-toolexeclibgohashDATA \ + uninstall-toolexeclibgoexpDATA uninstall-toolexeclibgogoDATA \ + uninstall-toolexeclibgohashDATA \ uninstall-toolexeclibgohtmlDATA \ uninstall-toolexeclibgoimageDATA \ uninstall-toolexeclibgoindexDATA uninstall-toolexeclibgoioDATA \ @@ -5230,6 +5269,26 @@ crypto/x509/pkix/check: $(CHECK_DEPS) @$(CHECK) .PHONY: crypto/x509/pkix/check +@go_include@ database/sql.lo.dep +database/sql.lo.dep: $(go_database_sql_files) + $(BUILDDEPS) +database/sql.lo: $(go_database_sql_files) + $(BUILDPACKAGE) +database/sql/check: $(CHECK_DEPS) + @$(MKDIR_P) database/sql + @$(CHECK) +.PHONY: database/sql/check + +@go_include@ database/sql/driver.lo.dep +database/sql/driver.lo.dep: $(go_database_sql_driver_files) + $(BUILDDEPS) +database/sql/driver.lo: $(go_database_sql_driver_files) + $(BUILDPACKAGE) +database/sql/driver/check: $(CHECK_DEPS) + @$(MKDIR_P) database/sql/driver + @$(CHECK) +.PHONY: database/sql/driver/check + @go_include@ debug/dwarf.lo.dep debug/dwarf.lo.dep: $(go_debug_dwarf_files) $(BUILDDEPS) @@ -5440,16 +5499,6 @@ exp/spdy/check: $(CHECK_DEPS) @$(CHECK) .PHONY: exp/spdy/check -@go_include@ exp/sql.lo.dep -exp/sql.lo.dep: $(go_exp_sql_files) - $(BUILDDEPS) -exp/sql.lo: $(go_exp_sql_files) - $(BUILDPACKAGE) -exp/sql/check: $(CHECK_DEPS) - @$(MKDIR_P) exp/sql - @$(CHECK) -.PHONY: exp/sql/check - @go_include@ exp/ssh.lo.dep exp/ssh.lo.dep: $(go_exp_ssh_files) $(BUILDDEPS) @@ -5480,6 +5529,16 @@ exp/types/check: $(CHECK_DEPS) @$(CHECK) .PHONY: exp/types/check +@go_include@ exp/utf8string.lo.dep +exp/utf8string.lo.dep: $(go_exp_utf8string_files) + $(BUILDDEPS) +exp/utf8string.lo: $(go_exp_utf8string_files) + $(BUILDPACKAGE) +exp/utf8string/check: $(CHECK_DEPS) + @$(MKDIR_P) exp/utf8string + @$(CHECK) +.PHONY: exp/utf8string/check + @go_include@ exp/inotify.lo.dep exp/inotify.lo.dep: $(go_exp_inotify_files) $(BUILDDEPS) @@ -5490,16 +5549,6 @@ exp/inotify/check: $(CHECK_DEPS) @$(CHECK) .PHONY: exp/inotify/check -@go_include@ exp/sql/driver.lo.dep -exp/sql/driver.lo.dep: $(go_exp_sql_driver_files) - $(BUILDDEPS) -exp/sql/driver.lo: $(go_exp_sql_driver_files) - $(BUILDPACKAGE) -exp/sql/driver/check: $(CHECK_DEPS) - @$(MKDIR_P) exp/sql/driver - @$(CHECK) -.PHONY: exp/sql/driver/check - @go_include@ html/template.lo.dep html/template.lo.dep: $(go_html_template_files) $(BUILDDEPS) @@ -6249,6 +6298,12 @@ crypto/openpgp/s2k.gox: crypto/openpgp/s2k.lo crypto/x509/pkix.gox: crypto/x509/pkix.lo $(BUILDGOX) +database/sql.gox: database/sql.lo + $(BUILDGOX) + +database/sql/driver.gox: database/sql/driver.lo + $(BUILDGOX) + debug/dwarf.gox: debug/dwarf.lo $(BUILDGOX) debug/elf.gox: debug/elf.lo @@ -6295,16 +6350,13 @@ exp/proxy.gox: exp/proxy.lo $(BUILDGOX) exp/spdy.gox: exp/spdy.lo $(BUILDGOX) -exp/sql.gox: exp/sql.lo - $(BUILDGOX) exp/ssh.gox: exp/ssh.lo $(BUILDGOX) exp/terminal.gox: exp/terminal.lo $(BUILDGOX) exp/types.gox: exp/types.lo $(BUILDGOX) - -exp/sql/driver.gox: exp/sql/driver.lo +exp/utf8string.gox: exp/utf8string.lo $(BUILDGOX) html/template.gox: html/template.lo diff --git a/libgo/go/bytes/example_test.go b/libgo/go/bytes/example_test.go index 02da1ac..0234a01 100644 --- a/libgo/go/bytes/example_test.go +++ b/libgo/go/bytes/example_test.go @@ -1,3 +1,7 @@ +// 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 bytes_test import ( diff --git a/libgo/go/container/heap/heap.go b/libgo/go/container/heap/heap.go index ca91139..7af636b 100644 --- a/libgo/go/container/heap/heap.go +++ b/libgo/go/container/heap/heap.go @@ -3,7 +3,13 @@ // license that can be found in the LICENSE file. // Package heap provides heap operations for any type that implements -// heap.Interface. +// heap.Interface. A heap is a tree with the property that each node is the +// highest-valued node in its subtree. +// +// A heap is a common way to impement a priority queue. To build a priority +// queue, implement the Heap interface with the (negative) priority as the +// ordering for the Less method, so Push adds items while Pop removes the +// highest-priority item from the queue. // package heap diff --git a/libgo/go/crypto/ecdsa/ecdsa.go b/libgo/go/crypto/ecdsa/ecdsa.go index 2f19999..d2f7d8f 100644 --- a/libgo/go/crypto/ecdsa/ecdsa.go +++ b/libgo/go/crypto/ecdsa/ecdsa.go @@ -20,7 +20,7 @@ import ( // PublicKey represents an ECDSA public key. type PublicKey struct { - *elliptic.Curve + elliptic.Curve X, Y *big.Int } @@ -34,22 +34,23 @@ var one = new(big.Int).SetInt64(1) // randFieldElement returns a random element of the field underlying the given // curve using the procedure given in [NSA] A.2.1. -func randFieldElement(c *elliptic.Curve, rand io.Reader) (k *big.Int, err error) { - b := make([]byte, c.BitSize/8+8) +func randFieldElement(c elliptic.Curve, rand io.Reader) (k *big.Int, err error) { + params := c.Params() + b := make([]byte, params.BitSize/8+8) _, err = io.ReadFull(rand, b) if err != nil { return } k = new(big.Int).SetBytes(b) - n := new(big.Int).Sub(c.N, one) + n := new(big.Int).Sub(params.N, one) k.Mod(k, n) k.Add(k, one) return } // GenerateKey generates a public&private key pair. -func GenerateKey(c *elliptic.Curve, rand io.Reader) (priv *PrivateKey, err error) { +func GenerateKey(c elliptic.Curve, rand io.Reader) (priv *PrivateKey, err error) { k, err := randFieldElement(c, rand) if err != nil { return @@ -66,8 +67,8 @@ func GenerateKey(c *elliptic.Curve, rand io.Reader) (priv *PrivateKey, err error // about how this is done. [NSA] suggests that this is done in the obvious // manner, but [SECG] truncates the hash to the bit-length of the curve order // first. We follow [SECG] because that's what OpenSSL does. -func hashToInt(hash []byte, c *elliptic.Curve) *big.Int { - orderBits := c.N.BitLen() +func hashToInt(hash []byte, c elliptic.Curve) *big.Int { + orderBits := c.Params().N.BitLen() orderBytes := (orderBits + 7) / 8 if len(hash) > orderBytes { hash = hash[:orderBytes] @@ -88,6 +89,7 @@ func hashToInt(hash []byte, c *elliptic.Curve) *big.Int { func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) { // See [NSA] 3.4.1 c := priv.PublicKey.Curve + N := c.Params().N var k, kInv *big.Int for { @@ -98,9 +100,9 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err return } - kInv = new(big.Int).ModInverse(k, c.N) + kInv = new(big.Int).ModInverse(k, N) r, _ = priv.Curve.ScalarBaseMult(k.Bytes()) - r.Mod(r, priv.Curve.N) + r.Mod(r, N) if r.Sign() != 0 { break } @@ -110,7 +112,7 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err s = new(big.Int).Mul(priv.D, r) s.Add(s, e) s.Mul(s, kInv) - s.Mod(s, priv.PublicKey.Curve.N) + s.Mod(s, N) if s.Sign() != 0 { break } @@ -124,15 +126,16 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool { // See [NSA] 3.4.2 c := pub.Curve + N := c.Params().N if r.Sign() == 0 || s.Sign() == 0 { return false } - if r.Cmp(c.N) >= 0 || s.Cmp(c.N) >= 0 { + if r.Cmp(N) >= 0 || s.Cmp(N) >= 0 { return false } e := hashToInt(hash, c) - w := new(big.Int).ModInverse(s, c.N) + w := new(big.Int).ModInverse(s, N) u1 := e.Mul(e, w) u2 := w.Mul(r, w) @@ -143,6 +146,6 @@ func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool { return false } x, _ := c.Add(x1, y1, x2, y2) - x.Mod(x, c.N) + x.Mod(x, N) return x.Cmp(r) == 0 } diff --git a/libgo/go/crypto/ecdsa/ecdsa_test.go b/libgo/go/crypto/ecdsa/ecdsa_test.go index 45433e1..3a2b3ef 100644 --- a/libgo/go/crypto/ecdsa/ecdsa_test.go +++ b/libgo/go/crypto/ecdsa/ecdsa_test.go @@ -13,7 +13,7 @@ import ( "testing" ) -func testKeyGeneration(t *testing.T, c *elliptic.Curve, tag string) { +func testKeyGeneration(t *testing.T, c elliptic.Curve, tag string) { priv, err := GenerateKey(c, rand.Reader) if err != nil { t.Errorf("%s: error: %s", tag, err) @@ -34,7 +34,7 @@ func TestKeyGeneration(t *testing.T) { testKeyGeneration(t, elliptic.P521(), "p521") } -func testSignAndVerify(t *testing.T, c *elliptic.Curve, tag string) { +func testSignAndVerify(t *testing.T, c elliptic.Curve, tag string) { priv, _ := GenerateKey(c, rand.Reader) hashed := []byte("testing") diff --git a/libgo/go/crypto/elliptic/elliptic.go b/libgo/go/crypto/elliptic/elliptic.go index b7232a2..30835a9 100644 --- a/libgo/go/crypto/elliptic/elliptic.go +++ b/libgo/go/crypto/elliptic/elliptic.go @@ -21,7 +21,25 @@ import ( // A Curve represents a short-form Weierstrass curve with a=-3. // See http://www.hyperelliptic.org/EFD/g1p/auto-shortw.html -type Curve struct { +type Curve interface { + // Params returns the parameters for the curve. + Params() *CurveParams + // IsOnCurve returns true if the given (x,y) lies on the curve. + IsOnCurve(x, y *big.Int) bool + // Add returns the sum of (x1,y1) and (x2,y2) + Add(x1, y1, x2, y2 *big.Int) (x, y *big.Int) + // Double returns 2*(x,y) + Double(x1, y1 *big.Int) (x, y *big.Int) + // ScalarMult returns k*(Bx,By) where k is a number in big-endian form. + ScalarMult(x1, y1 *big.Int, scalar []byte) (x, y *big.Int) + // ScalarBaseMult returns k*G, where G is the base point of the group and k + // is an integer in big-endian form. + ScalarBaseMult(scalar []byte) (x, y *big.Int) +} + +// CurveParams contains the parameters of an elliptic curve and also provides +// a generic, non-constant time implementation of Curve. +type CurveParams struct { P *big.Int // the order of the underlying field N *big.Int // the order of the base point B *big.Int // the constant of the curve equation @@ -29,8 +47,11 @@ type Curve struct { BitSize int // the size of the underlying field } -// IsOnCurve returns true if the given (x,y) lies on the curve. -func (curve *Curve) IsOnCurve(x, y *big.Int) bool { +func (curve *CurveParams) Params() *CurveParams { + return curve +} + +func (curve *CurveParams) IsOnCurve(x, y *big.Int) bool { // y² = x³ - 3x + b y2 := new(big.Int).Mul(y, y) y2.Mod(y2, curve.P) @@ -50,7 +71,7 @@ func (curve *Curve) IsOnCurve(x, y *big.Int) bool { // affineFromJacobian reverses the Jacobian transform. See the comment at the // top of the file. -func (curve *Curve) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big.Int) { +func (curve *CurveParams) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big.Int) { zinv := new(big.Int).ModInverse(z, curve.P) zinvsq := new(big.Int).Mul(zinv, zinv) @@ -62,15 +83,14 @@ func (curve *Curve) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big.Int) { return } -// Add returns the sum of (x1,y1) and (x2,y2) -func (curve *Curve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) { +func (curve *CurveParams) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) { z := new(big.Int).SetInt64(1) return curve.affineFromJacobian(curve.addJacobian(x1, y1, z, x2, y2, z)) } // addJacobian takes two points in Jacobian coordinates, (x1, y1, z1) and // (x2, y2, z2) and returns their sum, also in Jacobian form. -func (curve *Curve) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int, *big.Int, *big.Int) { +func (curve *CurveParams) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int, *big.Int, *big.Int) { // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl z1z1 := new(big.Int).Mul(z1, z1) z1z1.Mod(z1z1, curve.P) @@ -133,15 +153,14 @@ func (curve *Curve) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int, *big return x3, y3, z3 } -// Double returns 2*(x,y) -func (curve *Curve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) { +func (curve *CurveParams) Double(x1, y1 *big.Int) (*big.Int, *big.Int) { z1 := new(big.Int).SetInt64(1) return curve.affineFromJacobian(curve.doubleJacobian(x1, y1, z1)) } // doubleJacobian takes a point in Jacobian coordinates, (x, y, z), and // returns its double, also in Jacobian form. -func (curve *Curve) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, *big.Int) { +func (curve *CurveParams) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, *big.Int) { // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b delta := new(big.Int).Mul(z, z) delta.Mod(delta, curve.P) @@ -199,8 +218,7 @@ func (curve *Curve) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, *big.I return x3, y3, z3 } -// ScalarMult returns k*(Bx,By) where k is a number in big-endian form. -func (curve *Curve) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) { +func (curve *CurveParams) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) { // We have a slight problem in that the identity of the group (the // point at infinity) cannot be represented in (x, y) form on a finite // machine. Thus the standard add/double algorithm has to be tweaked @@ -238,18 +256,17 @@ func (curve *Curve) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) { return curve.affineFromJacobian(x, y, z) } -// ScalarBaseMult returns k*G, where G is the base point of the group and k is -// an integer in big-endian form. -func (curve *Curve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) { +func (curve *CurveParams) ScalarBaseMult(k []byte) (*big.Int, *big.Int) { return curve.ScalarMult(curve.Gx, curve.Gy, k) } var mask = []byte{0xff, 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f} -// GenerateKey returns a public/private key pair. The private key is generated -// using the given reader, which must return random data. -func (curve *Curve) GenerateKey(rand io.Reader) (priv []byte, x, y *big.Int, err error) { - byteLen := (curve.BitSize + 7) >> 3 +// GenerateKey returns a public/private key pair. The private key is +// generated using the given reader, which must return random data. +func GenerateKey(curve Curve, rand io.Reader) (priv []byte, x, y *big.Int, err error) { + bitSize := curve.Params().BitSize + byteLen := (bitSize + 7) >> 3 priv = make([]byte, byteLen) for x == nil { @@ -259,7 +276,7 @@ func (curve *Curve) GenerateKey(rand io.Reader) (priv []byte, x, y *big.Int, err } // We have to mask off any excess bits in the case that the size of the // underlying field is not a whole number of bytes. - priv[0] &= mask[curve.BitSize%8] + priv[0] &= mask[bitSize%8] // This is because, in tests, rand will return all zeros and we don't // want to get the point at infinity and loop forever. priv[1] ^= 0x42 @@ -268,10 +285,9 @@ func (curve *Curve) GenerateKey(rand io.Reader) (priv []byte, x, y *big.Int, err return } -// Marshal converts a point into the form specified in section 4.3.6 of ANSI -// X9.62. -func (curve *Curve) Marshal(x, y *big.Int) []byte { - byteLen := (curve.BitSize + 7) >> 3 +// Marshal converts a point into the form specified in section 4.3.6 of ANSI X9.62. +func Marshal(curve Curve, x, y *big.Int) []byte { + byteLen := (curve.Params().BitSize + 7) >> 3 ret := make([]byte, 1+2*byteLen) ret[0] = 4 // uncompressed point @@ -283,10 +299,9 @@ func (curve *Curve) Marshal(x, y *big.Int) []byte { return ret } -// Unmarshal converts a point, serialized by Marshal, into an x, y pair. On -// error, x = nil. -func (curve *Curve) Unmarshal(data []byte) (x, y *big.Int) { - byteLen := (curve.BitSize + 7) >> 3 +// Unmarshal converts a point, serialized by Marshal, into an x, y pair. On error, x = nil. +func Unmarshal(curve Curve, data []byte) (x, y *big.Int) { + byteLen := (curve.Params().BitSize + 7) >> 3 if len(data) != 1+2*byteLen { return } @@ -299,10 +314,9 @@ func (curve *Curve) Unmarshal(data []byte) (x, y *big.Int) { } var initonce sync.Once -var p224 *Curve -var p256 *Curve -var p384 *Curve -var p521 *Curve +var p256 *CurveParams +var p384 *CurveParams +var p521 *CurveParams func initAll() { initP224() @@ -311,20 +325,9 @@ func initAll() { initP521() } -func initP224() { - // See FIPS 186-3, section D.2.2 - p224 = new(Curve) - p224.P, _ = new(big.Int).SetString("26959946667150639794667015087019630673557916260026308143510066298881", 10) - p224.N, _ = new(big.Int).SetString("26959946667150639794667015087019625940457807714424391721682722368061", 10) - p224.B, _ = new(big.Int).SetString("b4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4", 16) - p224.Gx, _ = new(big.Int).SetString("b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21", 16) - p224.Gy, _ = new(big.Int).SetString("bd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34", 16) - p224.BitSize = 224 -} - func initP256() { // See FIPS 186-3, section D.2.3 - p256 = new(Curve) + p256 = new(CurveParams) p256.P, _ = new(big.Int).SetString("115792089210356248762697446949407573530086143415290314195533631308867097853951", 10) p256.N, _ = new(big.Int).SetString("115792089210356248762697446949407573529996955224135760342422259061068512044369", 10) p256.B, _ = new(big.Int).SetString("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16) @@ -335,7 +338,7 @@ func initP256() { func initP384() { // See FIPS 186-3, section D.2.4 - p384 = new(Curve) + p384 = new(CurveParams) p384.P, _ = new(big.Int).SetString("39402006196394479212279040100143613805079739270465446667948293404245721771496870329047266088258938001861606973112319", 10) p384.N, _ = new(big.Int).SetString("39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942643", 10) p384.B, _ = new(big.Int).SetString("b3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef", 16) @@ -346,7 +349,7 @@ func initP384() { func initP521() { // See FIPS 186-3, section D.2.5 - p521 = new(Curve) + p521 = new(CurveParams) p521.P, _ = new(big.Int).SetString("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151", 10) p521.N, _ = new(big.Int).SetString("6864797660130609714981900799081393217269435300143305409394463459185543183397655394245057746333217197532963996371363321113864768612440380340372808892707005449", 10) p521.B, _ = new(big.Int).SetString("051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00", 16) @@ -355,26 +358,20 @@ func initP521() { p521.BitSize = 521 } -// P224 returns a Curve which implements P-224 (see FIPS 186-3, section D.2.2) -func P224() *Curve { - initonce.Do(initAll) - return p224 -} - // P256 returns a Curve which implements P-256 (see FIPS 186-3, section D.2.3) -func P256() *Curve { +func P256() Curve { initonce.Do(initAll) return p256 } // P384 returns a Curve which implements P-384 (see FIPS 186-3, section D.2.4) -func P384() *Curve { +func P384() Curve { initonce.Do(initAll) return p384 } // P256 returns a Curve which implements P-521 (see FIPS 186-3, section D.2.5) -func P521() *Curve { +func P521() Curve { initonce.Do(initAll) return p521 } diff --git a/libgo/go/crypto/elliptic/elliptic_test.go b/libgo/go/crypto/elliptic/elliptic_test.go index a68a380..c23af75 100644 --- a/libgo/go/crypto/elliptic/elliptic_test.go +++ b/libgo/go/crypto/elliptic/elliptic_test.go @@ -13,7 +13,7 @@ import ( func TestOnCurve(t *testing.T) { p224 := P224() - if !p224.IsOnCurve(p224.Gx, p224.Gy) { + if !p224.IsOnCurve(p224.Params().Gx, p224.Params().Gy) { t.Errorf("FAIL") } } @@ -295,7 +295,25 @@ func TestBaseMult(t *testing.T) { } x, y := p224.ScalarBaseMult(k.Bytes()) if fmt.Sprintf("%x", x) != e.x || fmt.Sprintf("%x", y) != e.y { - t.Errorf("%d: bad output for k=%s: got (%x, %s), want (%x, %s)", i, e.k, x, y, e.x, e.y) + t.Errorf("%d: bad output for k=%s: got (%x, %x), want (%s, %s)", i, e.k, x, y, e.x, e.y) + } + if testing.Short() && i > 5 { + break + } + } +} + +func TestGenericBaseMult(t *testing.T) { + // We use the P224 CurveParams directly in order to test the generic implementation. + p224 := P224().Params() + for i, e := range p224BaseMultTests { + k, ok := new(big.Int).SetString(e.k, 10) + if !ok { + t.Errorf("%d: bad value for k: %s", i, e.k) + } + x, y := p224.ScalarBaseMult(k.Bytes()) + if fmt.Sprintf("%x", x) != e.x || fmt.Sprintf("%x", y) != e.y { + t.Errorf("%d: bad output for k=%s: got (%x, %x), want (%s, %s)", i, e.k, x, y, e.x, e.y) } if testing.Short() && i > 5 { break @@ -316,13 +334,13 @@ func BenchmarkBaseMult(b *testing.B) { func TestMarshal(t *testing.T) { p224 := P224() - _, x, y, err := p224.GenerateKey(rand.Reader) + _, x, y, err := GenerateKey(p224, rand.Reader) if err != nil { t.Error(err) return } - serialized := p224.Marshal(x, y) - xx, yy := p224.Unmarshal(serialized) + serialized := Marshal(p224, x, y) + xx, yy := Unmarshal(p224, serialized) if xx == nil { t.Error("failed to unmarshal") return diff --git a/libgo/go/crypto/elliptic/p224.go b/libgo/go/crypto/elliptic/p224.go new file mode 100644 index 0000000..08db5bc --- /dev/null +++ b/libgo/go/crypto/elliptic/p224.go @@ -0,0 +1,685 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package elliptic + +// This is a constant-time, 32-bit implementation of P224. See FIPS 186-3, +// section D.2.2. +// +// See http://www.imperialviolet.org/2010/12/04/ecc.html ([1]) for background. + +import ( + "math/big" +) + +var p224 p224Curve + +type p224Curve struct { + *CurveParams + gx, gy, b p224FieldElement +} + +func initP224() { + // See FIPS 186-3, section D.2.2 + p224.CurveParams = new(CurveParams) + p224.P, _ = new(big.Int).SetString("26959946667150639794667015087019630673557916260026308143510066298881", 10) + p224.N, _ = new(big.Int).SetString("26959946667150639794667015087019625940457807714424391721682722368061", 10) + p224.B, _ = new(big.Int).SetString("b4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4", 16) + p224.Gx, _ = new(big.Int).SetString("b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21", 16) + p224.Gy, _ = new(big.Int).SetString("bd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34", 16) + p224.BitSize = 224 + + p224FromBig(&p224.gx, p224.Gx) + p224FromBig(&p224.gy, p224.Gy) + p224FromBig(&p224.b, p224.B) +} + +// P224 returns a Curve which implements P-224 (see FIPS 186-3, section D.2.2) +func P224() Curve { + initonce.Do(initAll) + return p224 +} + +func (curve p224Curve) Params() *CurveParams { + return curve.CurveParams +} + +func (curve p224Curve) IsOnCurve(bigX, bigY *big.Int) bool { + var x, y p224FieldElement + p224FromBig(&x, bigX) + p224FromBig(&y, bigY) + + // y² = x³ - 3x + b + var tmp p224LargeFieldElement + var x3 p224FieldElement + p224Square(&x3, &x, &tmp) + p224Mul(&x3, &x3, &x, &tmp) + + for i := 0; i < 8; i++ { + x[i] *= 3 + } + p224Sub(&x3, &x3, &x) + p224Reduce(&x3) + p224Add(&x3, &x3, &curve.b) + p224Contract(&x3, &x3) + + p224Square(&y, &y, &tmp) + p224Contract(&y, &y) + + for i := 0; i < 8; i++ { + if y[i] != x3[i] { + return false + } + } + return true +} + +func (p224Curve) Add(bigX1, bigY1, bigX2, bigY2 *big.Int) (x, y *big.Int) { + var x1, y1, z1, x2, y2, z2, x3, y3, z3 p224FieldElement + + p224FromBig(&x1, bigX1) + p224FromBig(&y1, bigY1) + z1[0] = 1 + p224FromBig(&x2, bigX2) + p224FromBig(&y2, bigY2) + z2[0] = 1 + + p224AddJacobian(&x3, &y3, &z3, &x1, &y1, &z1, &x2, &y2, &z2) + return p224ToAffine(&x3, &y3, &z3) +} + +func (p224Curve) Double(bigX1, bigY1 *big.Int) (x, y *big.Int) { + var x1, y1, z1, x2, y2, z2 p224FieldElement + + p224FromBig(&x1, bigX1) + p224FromBig(&y1, bigY1) + z1[0] = 1 + + p224DoubleJacobian(&x2, &y2, &z2, &x1, &y1, &z1) + return p224ToAffine(&x2, &y2, &z2) +} + +func (p224Curve) ScalarMult(bigX1, bigY1 *big.Int, scalar []byte) (x, y *big.Int) { + var x1, y1, z1, x2, y2, z2 p224FieldElement + + p224FromBig(&x1, bigX1) + p224FromBig(&y1, bigY1) + z1[0] = 1 + + p224ScalarMult(&x2, &y2, &z2, &x1, &y1, &z1, scalar) + return p224ToAffine(&x2, &y2, &z2) +} + +func (curve p224Curve) ScalarBaseMult(scalar []byte) (x, y *big.Int) { + var z1, x2, y2, z2 p224FieldElement + + z1[0] = 1 + p224ScalarMult(&x2, &y2, &z2, &curve.gx, &curve.gy, &z1, scalar) + return p224ToAffine(&x2, &y2, &z2) +} + +// Field element functions. +// +// The field that we're dealing with is ℤ/pℤ where p = 2**224 - 2**96 + 1. +// +// Field elements are represented by a FieldElement, which is a typedef to an +// array of 8 uint32's. The value of a FieldElement, a, is: +// a[0] + 2**28·a[1] + 2**56·a[1] + ... + 2**196·a[7] +// +// Using 28-bit limbs means that there's only 4 bits of headroom, which is less +// than we would really like. But it has the useful feature that we hit 2**224 +// exactly, making the reflections during a reduce much nicer. +type p224FieldElement [8]uint32 + +// p224Add computes *out = a+b +// +// a[i] + b[i] < 2**32 +func p224Add(out, a, b *p224FieldElement) { + for i := 0; i < 8; i++ { + out[i] = a[i] + b[i] + } +} + +const two31p3 = 1<<31 + 1<<3 +const two31m3 = 1<<31 - 1<<3 +const two31m15m3 = 1<<31 - 1<<15 - 1<<3 + +// p224ZeroModP31 is 0 mod p where bit 31 is set in all limbs so that we can +// subtract smaller amounts without underflow. See the section "Subtraction" in +// [1] for reasoning. +var p224ZeroModP31 = []uint32{two31p3, two31m3, two31m3, two31m15m3, two31m3, two31m3, two31m3, two31m3} + +// p224Sub computes *out = a-b +// +// a[i], b[i] < 2**30 +// out[i] < 2**32 +func p224Sub(out, a, b *p224FieldElement) { + for i := 0; i < 8; i++ { + out[i] = a[i] + p224ZeroModP31[i] - b[i] + } +} + +// LargeFieldElement also represents an element of the field. The limbs are +// still spaced 28-bits apart and in little-endian order. So the limbs are at +// 0, 28, 56, ..., 392 bits, each 64-bits wide. +type p224LargeFieldElement [15]uint64 + +const two63p35 = 1<<63 + 1<<35 +const two63m35 = 1<<63 - 1<<35 +const two63m35m19 = 1<<63 - 1<<35 - 1<<19 + +// p224ZeroModP63 is 0 mod p where bit 63 is set in all limbs. See the section +// "Subtraction" in [1] for why. +var p224ZeroModP63 = [8]uint64{two63p35, two63m35, two63m35, two63m35, two63m35m19, two63m35, two63m35, two63m35} + +const bottom12Bits = 0xfff +const bottom28Bits = 0xfffffff + +// p224Mul computes *out = a*b +// +// a[i] < 2**29, b[i] < 2**30 (or vice versa) +// out[i] < 2**29 +func p224Mul(out, a, b *p224FieldElement, tmp *p224LargeFieldElement) { + for i := 0; i < 15; i++ { + tmp[i] = 0 + } + + for i := 0; i < 8; i++ { + for j := 0; j < 8; j++ { + tmp[i+j] += uint64(a[i]) * uint64(b[j]) + } + } + + p224ReduceLarge(out, tmp) +} + +// Square computes *out = a*a +// +// a[i] < 2**29 +// out[i] < 2**29 +func p224Square(out, a *p224FieldElement, tmp *p224LargeFieldElement) { + for i := 0; i < 15; i++ { + tmp[i] = 0 + } + + for i := 0; i < 8; i++ { + for j := 0; j <= i; j++ { + r := uint64(a[i]) * uint64(a[j]) + if i == j { + tmp[i+j] += r + } else { + tmp[i+j] += r << 1 + } + } + } + + p224ReduceLarge(out, tmp) +} + +// ReduceLarge converts a p224LargeFieldElement to a p224FieldElement. +// +// in[i] < 2**62 +func p224ReduceLarge(out *p224FieldElement, in *p224LargeFieldElement) { + for i := 0; i < 8; i++ { + in[i] += p224ZeroModP63[i] + } + + // Elimintate the coefficients at 2**224 and greater. + for i := 14; i >= 8; i-- { + in[i-8] -= in[i] + in[i-5] += (in[i] & 0xffff) << 12 + in[i-4] += in[i] >> 16 + } + in[8] = 0 + // in[0..8] < 2**64 + + // As the values become small enough, we start to store them in |out| + // and use 32-bit operations. + for i := 1; i < 8; i++ { + in[i+1] += in[i] >> 28 + out[i] = uint32(in[i] & bottom28Bits) + } + in[0] -= in[8] + out[3] += uint32(in[8]&0xffff) << 12 + out[4] += uint32(in[8] >> 16) + // in[0] < 2**64 + // out[3] < 2**29 + // out[4] < 2**29 + // out[1,2,5..7] < 2**28 + + out[0] = uint32(in[0] & bottom28Bits) + out[1] += uint32((in[0] >> 28) & bottom28Bits) + out[2] += uint32(in[0] >> 56) + // out[0] < 2**28 + // out[1..4] < 2**29 + // out[5..7] < 2**28 +} + +// Reduce reduces the coefficients of a to smaller bounds. +// +// On entry: a[i] < 2**31 + 2**30 +// On exit: a[i] < 2**29 +func p224Reduce(a *p224FieldElement) { + for i := 0; i < 7; i++ { + a[i+1] += a[i] >> 28 + a[i] &= bottom28Bits + } + top := a[7] >> 28 + a[7] &= bottom28Bits + + // top < 2**4 + mask := top + mask |= mask >> 2 + mask |= mask >> 1 + mask <<= 31 + mask = uint32(int32(mask) >> 31) + // Mask is all ones if top != 0, all zero otherwise + + a[0] -= top + a[3] += top << 12 + + // We may have just made a[0] negative but, if we did, then we must + // have added something to a[3], this it's > 2**12. Therefore we can + // carry down to a[0]. + a[3] -= 1 & mask + a[2] += mask & (1<<28 - 1) + a[1] += mask & (1<<28 - 1) + a[0] += mask & (1 << 28) +} + +// p224Invert calcuates *out = in**-1 by computing in**(2**224 - 2**96 - 1), +// i.e. Fermat's little theorem. +func p224Invert(out, in *p224FieldElement) { + var f1, f2, f3, f4 p224FieldElement + var c p224LargeFieldElement + + p224Square(&f1, in, &c) // 2 + p224Mul(&f1, &f1, in, &c) // 2**2 - 1 + p224Square(&f1, &f1, &c) // 2**3 - 2 + p224Mul(&f1, &f1, in, &c) // 2**3 - 1 + p224Square(&f2, &f1, &c) // 2**4 - 2 + p224Square(&f2, &f2, &c) // 2**5 - 4 + p224Square(&f2, &f2, &c) // 2**6 - 8 + p224Mul(&f1, &f1, &f2, &c) // 2**6 - 1 + p224Square(&f2, &f1, &c) // 2**7 - 2 + for i := 0; i < 5; i++ { // 2**12 - 2**6 + p224Square(&f2, &f2, &c) + } + p224Mul(&f2, &f2, &f1, &c) // 2**12 - 1 + p224Square(&f3, &f2, &c) // 2**13 - 2 + for i := 0; i < 11; i++ { // 2**24 - 2**12 + p224Square(&f3, &f3, &c) + } + p224Mul(&f2, &f3, &f2, &c) // 2**24 - 1 + p224Square(&f3, &f2, &c) // 2**25 - 2 + for i := 0; i < 23; i++ { // 2**48 - 2**24 + p224Square(&f3, &f3, &c) + } + p224Mul(&f3, &f3, &f2, &c) // 2**48 - 1 + p224Square(&f4, &f3, &c) // 2**49 - 2 + for i := 0; i < 47; i++ { // 2**96 - 2**48 + p224Square(&f4, &f4, &c) + } + p224Mul(&f3, &f3, &f4, &c) // 2**96 - 1 + p224Square(&f4, &f3, &c) // 2**97 - 2 + for i := 0; i < 23; i++ { // 2**120 - 2**24 + p224Square(&f4, &f4, &c) + } + p224Mul(&f2, &f4, &f2, &c) // 2**120 - 1 + for i := 0; i < 6; i++ { // 2**126 - 2**6 + p224Square(&f2, &f2, &c) + } + p224Mul(&f1, &f1, &f2, &c) // 2**126 - 1 + p224Square(&f1, &f1, &c) // 2**127 - 2 + p224Mul(&f1, &f1, in, &c) // 2**127 - 1 + for i := 0; i < 97; i++ { // 2**224 - 2**97 + p224Square(&f1, &f1, &c) + } + p224Mul(out, &f1, &f3, &c) // 2**224 - 2**96 - 1 +} + +// p224Contract converts a FieldElement to its unique, minimal form. +// +// On entry, in[i] < 2**32 +// On exit, in[i] < 2**28 +func p224Contract(out, in *p224FieldElement) { + copy(out[:], in[:]) + + for i := 0; i < 7; i++ { + out[i+1] += out[i] >> 28 + out[i] &= bottom28Bits + } + top := out[7] >> 28 + out[7] &= bottom28Bits + + out[0] -= top + out[3] += top << 12 + + // We may just have made out[i] negative. So we carry down. If we made + // out[0] negative then we know that out[3] is sufficiently positive + // because we just added to it. + for i := 0; i < 3; i++ { + mask := uint32(int32(out[i]) >> 31) + out[i] += (1 << 28) & mask + out[i+1] -= 1 & mask + } + + // Now we see if the value is >= p and, if so, subtract p. + + // First we build a mask from the top four limbs, which must all be + // equal to bottom28Bits if the whole value is >= p. If top4AllOnes + // ends up with any zero bits in the bottom 28 bits, then this wasn't + // true. + top4AllOnes := uint32(0xffffffff) + for i := 4; i < 8; i++ { + top4AllOnes &= (out[i] & bottom28Bits) - 1 + } + top4AllOnes |= 0xf0000000 + // Now we replicate any zero bits to all the bits in top4AllOnes. + top4AllOnes &= top4AllOnes >> 16 + top4AllOnes &= top4AllOnes >> 8 + top4AllOnes &= top4AllOnes >> 4 + top4AllOnes &= top4AllOnes >> 2 + top4AllOnes &= top4AllOnes >> 1 + top4AllOnes = uint32(int32(top4AllOnes<<31) >> 31) + + // Now we test whether the bottom three limbs are non-zero. + bottom3NonZero := out[0] | out[1] | out[2] + bottom3NonZero |= bottom3NonZero >> 16 + bottom3NonZero |= bottom3NonZero >> 8 + bottom3NonZero |= bottom3NonZero >> 4 + bottom3NonZero |= bottom3NonZero >> 2 + bottom3NonZero |= bottom3NonZero >> 1 + bottom3NonZero = uint32(int32(bottom3NonZero<<31) >> 31) + + // Everything depends on the value of out[3]. + // If it's > 0xffff000 and top4AllOnes != 0 then the whole value is >= p + // If it's = 0xffff000 and top4AllOnes != 0 and bottom3NonZero != 0, + // then the whole value is >= p + // If it's < 0xffff000, then the whole value is < p + n := out[3] - 0xffff000 + out3Equal := n + out3Equal |= out3Equal >> 16 + out3Equal |= out3Equal >> 8 + out3Equal |= out3Equal >> 4 + out3Equal |= out3Equal >> 2 + out3Equal |= out3Equal >> 1 + out3Equal = ^uint32(int32(out3Equal<<31) >> 31) + + // If out[3] > 0xffff000 then n's MSB will be zero. + out3GT := ^uint32(int32(n<<31) >> 31) + + mask := top4AllOnes & ((out3Equal & bottom3NonZero) | out3GT) + out[0] -= 1 & mask + out[3] -= 0xffff000 & mask + out[4] -= 0xfffffff & mask + out[5] -= 0xfffffff & mask + out[6] -= 0xfffffff & mask + out[7] -= 0xfffffff & mask +} + +// Group element functions. +// +// These functions deal with group elements. The group is an elliptic curve +// group with a = -3 defined in FIPS 186-3, section D.2.2. + +// p224AddJacobian computes *out = a+b where a != b. +func p224AddJacobian(x3, y3, z3, x1, y1, z1, x2, y2, z2 *p224FieldElement) { + // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-p224Add-2007-bl + var z1z1, z2z2, u1, u2, s1, s2, h, i, j, r, v p224FieldElement + var c p224LargeFieldElement + + // Z1Z1 = Z1² + p224Square(&z1z1, z1, &c) + // Z2Z2 = Z2² + p224Square(&z2z2, z2, &c) + // U1 = X1*Z2Z2 + p224Mul(&u1, x1, &z2z2, &c) + // U2 = X2*Z1Z1 + p224Mul(&u2, x2, &z1z1, &c) + // S1 = Y1*Z2*Z2Z2 + p224Mul(&s1, z2, &z2z2, &c) + p224Mul(&s1, y1, &s1, &c) + // S2 = Y2*Z1*Z1Z1 + p224Mul(&s2, z1, &z1z1, &c) + p224Mul(&s2, y2, &s2, &c) + // H = U2-U1 + p224Sub(&h, &u2, &u1) + p224Reduce(&h) + // I = (2*H)² + for j := 0; j < 8; j++ { + i[j] = h[j] << 1 + } + p224Reduce(&i) + p224Square(&i, &i, &c) + // J = H*I + p224Mul(&j, &h, &i, &c) + // r = 2*(S2-S1) + p224Sub(&r, &s2, &s1) + p224Reduce(&r) + for i := 0; i < 8; i++ { + r[i] <<= 1 + } + p224Reduce(&r) + // V = U1*I + p224Mul(&v, &u1, &i, &c) + // Z3 = ((Z1+Z2)²-Z1Z1-Z2Z2)*H + p224Add(&z1z1, &z1z1, &z2z2) + p224Add(&z2z2, z1, z2) + p224Reduce(&z2z2) + p224Square(&z2z2, &z2z2, &c) + p224Sub(z3, &z2z2, &z1z1) + p224Reduce(z3) + p224Mul(z3, z3, &h, &c) + // X3 = r²-J-2*V + for i := 0; i < 8; i++ { + z1z1[i] = v[i] << 1 + } + p224Add(&z1z1, &j, &z1z1) + p224Reduce(&z1z1) + p224Square(x3, &r, &c) + p224Sub(x3, x3, &z1z1) + p224Reduce(x3) + // Y3 = r*(V-X3)-2*S1*J + for i := 0; i < 8; i++ { + s1[i] <<= 1 + } + p224Mul(&s1, &s1, &j, &c) + p224Sub(&z1z1, &v, x3) + p224Reduce(&z1z1) + p224Mul(&z1z1, &z1z1, &r, &c) + p224Sub(y3, &z1z1, &s1) + p224Reduce(y3) +} + +// p224DoubleJacobian computes *out = a+a. +func p224DoubleJacobian(x3, y3, z3, x1, y1, z1 *p224FieldElement) { + var delta, gamma, beta, alpha, t p224FieldElement + var c p224LargeFieldElement + + p224Square(&delta, z1, &c) + p224Square(&gamma, y1, &c) + p224Mul(&beta, x1, &gamma, &c) + + // alpha = 3*(X1-delta)*(X1+delta) + p224Add(&t, x1, &delta) + for i := 0; i < 8; i++ { + t[i] += t[i] << 1 + } + p224Reduce(&t) + p224Sub(&alpha, x1, &delta) + p224Reduce(&alpha) + p224Mul(&alpha, &alpha, &t, &c) + + // Z3 = (Y1+Z1)²-gamma-delta + p224Add(z3, y1, z1) + p224Reduce(z3) + p224Square(z3, z3, &c) + p224Sub(z3, z3, &gamma) + p224Reduce(z3) + p224Sub(z3, z3, &delta) + p224Reduce(z3) + + // X3 = alpha²-8*beta + for i := 0; i < 8; i++ { + delta[i] = beta[i] << 3 + } + p224Reduce(&delta) + p224Square(x3, &alpha, &c) + p224Sub(x3, x3, &delta) + p224Reduce(x3) + + // Y3 = alpha*(4*beta-X3)-8*gamma² + for i := 0; i < 8; i++ { + beta[i] <<= 2 + } + p224Sub(&beta, &beta, x3) + p224Reduce(&beta) + p224Square(&gamma, &gamma, &c) + for i := 0; i < 8; i++ { + gamma[i] <<= 3 + } + p224Reduce(&gamma) + p224Mul(y3, &alpha, &beta, &c) + p224Sub(y3, y3, &gamma) + p224Reduce(y3) +} + +// p224CopyConditional sets *out = *in iff the least-significant-bit of control +// is true, and it runs in constant time. +func p224CopyConditional(out, in *p224FieldElement, control uint32) { + control <<= 31 + control = uint32(int32(control) >> 31) + + for i := 0; i < 8; i++ { + out[i] ^= (out[i] ^ in[i]) & control + } +} + +func p224ScalarMult(outX, outY, outZ, inX, inY, inZ *p224FieldElement, scalar []byte) { + var xx, yy, zz p224FieldElement + for i := 0; i < 8; i++ { + outZ[i] = 0 + } + + firstBit := uint32(1) + for _, byte := range scalar { + for bitNum := uint(0); bitNum < 8; bitNum++ { + p224DoubleJacobian(outX, outY, outZ, outX, outY, outZ) + bit := uint32((byte >> (7 - bitNum)) & 1) + p224AddJacobian(&xx, &yy, &zz, inX, inY, inZ, outX, outY, outZ) + p224CopyConditional(outX, inX, firstBit&bit) + p224CopyConditional(outY, inY, firstBit&bit) + p224CopyConditional(outZ, inZ, firstBit&bit) + p224CopyConditional(outX, &xx, ^firstBit&bit) + p224CopyConditional(outY, &yy, ^firstBit&bit) + p224CopyConditional(outZ, &zz, ^firstBit&bit) + firstBit = firstBit & ^bit + } + } +} + +// p224ToAffine converts from Jacobian to affine form. +func p224ToAffine(x, y, z *p224FieldElement) (*big.Int, *big.Int) { + var zinv, zinvsq, outx, outy p224FieldElement + var tmp p224LargeFieldElement + + isPointAtInfinity := true + for i := 0; i < 8; i++ { + if z[i] != 0 { + isPointAtInfinity = false + break + } + } + + if isPointAtInfinity { + return nil, nil + } + + p224Invert(&zinv, z) + p224Square(&zinvsq, &zinv, &tmp) + p224Mul(x, x, &zinvsq, &tmp) + p224Mul(&zinvsq, &zinvsq, &zinv, &tmp) + p224Mul(y, y, &zinvsq, &tmp) + + p224Contract(&outx, x) + p224Contract(&outy, y) + return p224ToBig(&outx), p224ToBig(&outy) +} + +// get28BitsFromEnd returns the least-significant 28 bits from buf>>shift, +// where buf is interpreted as a big-endian number. +func get28BitsFromEnd(buf []byte, shift uint) (uint32, []byte) { + var ret uint32 + + for i := uint(0); i < 4; i++ { + var b byte + if l := len(buf); l > 0 { + b = buf[l-1] + // We don't remove the byte if we're about to return and we're not + // reading all of it. + if i != 3 || shift == 4 { + buf = buf[:l-1] + } + } + ret |= uint32(b) << (8 * i) >> shift + } + ret &= bottom28Bits + return ret, buf +} + +// p224FromBig sets *out = *in. +func p224FromBig(out *p224FieldElement, in *big.Int) { + bytes := in.Bytes() + out[0], bytes = get28BitsFromEnd(bytes, 0) + out[1], bytes = get28BitsFromEnd(bytes, 4) + out[2], bytes = get28BitsFromEnd(bytes, 0) + out[3], bytes = get28BitsFromEnd(bytes, 4) + out[4], bytes = get28BitsFromEnd(bytes, 0) + out[5], bytes = get28BitsFromEnd(bytes, 4) + out[6], bytes = get28BitsFromEnd(bytes, 0) + out[7], bytes = get28BitsFromEnd(bytes, 4) +} + +// p224ToBig returns in as a big.Int. +func p224ToBig(in *p224FieldElement) *big.Int { + var buf [28]byte + buf[27] = byte(in[0]) + buf[26] = byte(in[0] >> 8) + buf[25] = byte(in[0] >> 16) + buf[24] = byte(((in[0] >> 24) & 0x0f) | (in[1]<<4)&0xf0) + + buf[23] = byte(in[1] >> 4) + buf[22] = byte(in[1] >> 12) + buf[21] = byte(in[1] >> 20) + + buf[20] = byte(in[2]) + buf[19] = byte(in[2] >> 8) + buf[18] = byte(in[2] >> 16) + buf[17] = byte(((in[2] >> 24) & 0x0f) | (in[3]<<4)&0xf0) + + buf[16] = byte(in[3] >> 4) + buf[15] = byte(in[3] >> 12) + buf[14] = byte(in[3] >> 20) + + buf[13] = byte(in[4]) + buf[12] = byte(in[4] >> 8) + buf[11] = byte(in[4] >> 16) + buf[10] = byte(((in[4] >> 24) & 0x0f) | (in[5]<<4)&0xf0) + + buf[9] = byte(in[5] >> 4) + buf[8] = byte(in[5] >> 12) + buf[7] = byte(in[5] >> 20) + + buf[6] = byte(in[6]) + buf[5] = byte(in[6] >> 8) + buf[4] = byte(in[6] >> 16) + buf[3] = byte(((in[6] >> 24) & 0x0f) | (in[7]<<4)&0xf0) + + buf[2] = byte(in[7] >> 4) + buf[1] = byte(in[7] >> 12) + buf[0] = byte(in[7] >> 20) + + return new(big.Int).SetBytes(buf[:]) +} diff --git a/libgo/go/crypto/elliptic/p224_test.go b/libgo/go/crypto/elliptic/p224_test.go new file mode 100644 index 0000000..4b26d16 --- /dev/null +++ b/libgo/go/crypto/elliptic/p224_test.go @@ -0,0 +1,47 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package elliptic + +import ( + "math/big" + "testing" +) + +var toFromBigTests = []string{ + "0", + "1", + "23", + "b70e0cb46bb4bf7f321390b94a03c1d356c01122343280d6105c1d21", + "706a46d476dcb76798e6046d89474788d164c18032d268fd10704fa6", +} + +func p224AlternativeToBig(in *p224FieldElement) *big.Int { + ret := new(big.Int) + tmp := new(big.Int) + + for i := uint(0); i < 8; i++ { + tmp.SetInt64(int64(in[i])) + tmp.Lsh(tmp, 28*i) + ret.Add(ret, tmp) + } + ret.Mod(ret, p224.P) + return ret +} + +func TestToFromBig(t *testing.T) { + for i, test := range toFromBigTests { + n, _ := new(big.Int).SetString(test, 16) + var x p224FieldElement + p224FromBig(&x, n) + m := p224ToBig(&x) + if n.Cmp(m) != 0 { + t.Errorf("#%d: %x != %x", i, n, m) + } + q := p224AlternativeToBig(&x) + if n.Cmp(q) != 0 { + t.Errorf("#%d: %x != %x (alternative)", i, n, m) + } + } +} diff --git a/libgo/go/crypto/hmac/hmac.go b/libgo/go/crypto/hmac/hmac.go index 6e7dd87..a97ce09 100644 --- a/libgo/go/crypto/hmac/hmac.go +++ b/libgo/go/crypto/hmac/hmac.go @@ -9,32 +9,20 @@ package hmac import ( - "crypto/md5" - "crypto/sha1" - "crypto/sha256" "hash" ) // FIPS 198: // http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf -// key is zero padded to 64 bytes -// ipad = 0x36 byte repeated to 64 bytes -// opad = 0x5c byte repeated to 64 bytes +// key is zero padded to the block size of the hash function +// ipad = 0x36 byte repeated for key length +// opad = 0x5c byte repeated for key length // hmac = H([key ^ opad] H([key ^ ipad] text)) -const ( - // NOTE(rsc): This constant is actually the - // underlying hash function's block size. - // HMAC is only conventionally used with - // MD5 and SHA1, and both use 64-byte blocks. - // The hash.Hash interface doesn't provide a - // way to find out the block size. - padSize = 64 -) - type hmac struct { size int + blocksize int key, tmp []byte outer, inner hash.Hash } @@ -43,7 +31,7 @@ func (h *hmac) tmpPad(xor byte) { for i, k := range h.key { h.tmp[i] = xor ^ k } - for i := len(h.key); i < padSize; i++ { + for i := len(h.key); i < h.blocksize; i++ { h.tmp[i] = xor } } @@ -52,7 +40,7 @@ func (h *hmac) Sum(in []byte) []byte { origLen := len(in) in = h.inner.Sum(in) h.tmpPad(0x5c) - copy(h.tmp[padSize:], in[origLen:]) + copy(h.tmp[h.blocksize:], in[origLen:]) h.outer.Reset() h.outer.Write(h.tmp) return h.outer.Sum(in[:origLen]) @@ -64,20 +52,23 @@ func (h *hmac) Write(p []byte) (n int, err error) { func (h *hmac) Size() int { return h.size } +func (h *hmac) BlockSize() int { return h.blocksize } + func (h *hmac) Reset() { h.inner.Reset() h.tmpPad(0x36) - h.inner.Write(h.tmp[0:padSize]) + h.inner.Write(h.tmp[0:h.blocksize]) } -// New returns a new HMAC hash using the given hash generator and key. +// New returns a new HMAC hash using the given hash.Hash type and key. func New(h func() hash.Hash, key []byte) hash.Hash { hm := new(hmac) hm.outer = h() hm.inner = h() hm.size = hm.inner.Size() - hm.tmp = make([]byte, padSize+hm.size) - if len(key) > padSize { + hm.blocksize = hm.inner.BlockSize() + hm.tmp = make([]byte, hm.blocksize+hm.size) + if len(key) > hm.blocksize { // If key is too big, hash it. hm.outer.Write(key) key = hm.outer.Sum(nil) @@ -87,12 +78,3 @@ func New(h func() hash.Hash, key []byte) hash.Hash { hm.Reset() return hm } - -// NewMD5 returns a new HMAC-MD5 hash using the given key. -func NewMD5(key []byte) hash.Hash { return New(md5.New, key) } - -// NewSHA1 returns a new HMAC-SHA1 hash using the given key. -func NewSHA1(key []byte) hash.Hash { return New(sha1.New, key) } - -// NewSHA256 returns a new HMAC-SHA256 hash using the given key. -func NewSHA256(key []byte) hash.Hash { return New(sha256.New, key) } diff --git a/libgo/go/crypto/hmac/hmac_test.go b/libgo/go/crypto/hmac/hmac_test.go index eac254b..0795741 100644 --- a/libgo/go/crypto/hmac/hmac_test.go +++ b/libgo/go/crypto/hmac/hmac_test.go @@ -5,13 +5,17 @@ package hmac import ( + "crypto/md5" + "crypto/sha1" + "crypto/sha256" + "crypto/sha512" "fmt" "hash" "testing" ) type hmacTest struct { - hash func([]byte) hash.Hash + hash func() hash.Hash key []byte in []byte out string @@ -21,7 +25,7 @@ var hmacTests = []hmacTest{ // Tests from US FIPS 198 // http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf { - NewSHA1, + sha1.New, []byte{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, @@ -36,7 +40,7 @@ var hmacTests = []hmacTest{ "4f4ca3d5d68ba7cc0a1208c9c61e9c5da0403c0a", }, { - NewSHA1, + sha1.New, []byte{ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, @@ -46,7 +50,7 @@ var hmacTests = []hmacTest{ "0922d3405faa3d194f82a45830737d5cc6c75d24", }, { - NewSHA1, + sha1.New, []byte{ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, @@ -68,7 +72,7 @@ var hmacTests = []hmacTest{ // Test from Plan 9. { - NewMD5, + md5.New, []byte("Jefe"), []byte("what do ya want for nothing?"), "750c783e6ab0b503eaa86e310a5db738", @@ -76,7 +80,7 @@ var hmacTests = []hmacTest{ // Tests from RFC 4231 { - NewSHA256, + sha256.New, []byte{ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, @@ -86,13 +90,13 @@ var hmacTests = []hmacTest{ "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7", }, { - NewSHA256, + sha256.New, []byte("Jefe"), []byte("what do ya want for nothing?"), "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843", }, { - NewSHA256, + sha256.New, []byte{ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, @@ -110,7 +114,7 @@ var hmacTests = []hmacTest{ "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe", }, { - NewSHA256, + sha256.New, []byte{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, @@ -129,7 +133,7 @@ var hmacTests = []hmacTest{ "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b", }, { - NewSHA256, + sha256.New, []byte{ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, @@ -153,7 +157,7 @@ var hmacTests = []hmacTest{ "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54", }, { - NewSHA256, + sha256.New, []byte{ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, @@ -178,11 +182,295 @@ var hmacTests = []hmacTest{ "be hashed before being used by the HMAC algorithm."), "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2", }, + + // Tests from http://csrc.nist.gov/groups/ST/toolkit/examples.html + // (truncated tag tests are left out) + { + sha1.New, + []byte{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + }, + []byte("Sample message for keylen=blocklen"), + "5fd596ee78d5553c8ff4e72d266dfd192366da29", + }, + { + sha1.New, + []byte{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, + }, + []byte("Sample message for keylen>3) + preMasterSecret := make([]byte, (ka.curve.Params().BitSize+7)>>3) xBytes := x.Bytes() copy(preMasterSecret[len(preMasterSecret)-len(xBytes):], xBytes) @@ -205,7 +205,7 @@ func (ka *ecdheRSAKeyAgreement) processServerKeyExchange(config *Config, clientH if publicLen+4 > len(skx.key) { return errServerKeyExchange } - ka.x, ka.y = ka.curve.Unmarshal(skx.key[4 : 4+publicLen]) + ka.x, ka.y = elliptic.Unmarshal(ka.curve, skx.key[4:4+publicLen]) if ka.x == nil { return errServerKeyExchange } @@ -229,16 +229,16 @@ func (ka *ecdheRSAKeyAgreement) generateClientKeyExchange(config *Config, client if ka.curve == nil { return nil, nil, errors.New("missing ServerKeyExchange message") } - priv, mx, my, err := ka.curve.GenerateKey(config.rand()) + priv, mx, my, err := elliptic.GenerateKey(ka.curve, config.rand()) if err != nil { return nil, nil, err } x, _ := ka.curve.ScalarMult(ka.x, ka.y, priv) - preMasterSecret := make([]byte, (ka.curve.BitSize+7)>>3) + preMasterSecret := make([]byte, (ka.curve.Params().BitSize+7)>>3) xBytes := x.Bytes() copy(preMasterSecret[len(preMasterSecret)-len(xBytes):], xBytes) - serialized := ka.curve.Marshal(mx, my) + serialized := elliptic.Marshal(ka.curve, mx, my) ckx := new(clientKeyExchangeMsg) ckx.ciphertext = make([]byte, 1+len(serialized)) diff --git a/libgo/go/crypto/tls/root_unix.go b/libgo/go/crypto/tls/root_unix.go index 5bbd982..acaf3dd 100644 --- a/libgo/go/crypto/tls/root_unix.go +++ b/libgo/go/crypto/tls/root_unix.go @@ -13,10 +13,11 @@ import ( // Possible certificate files; stop after finding one. var certFiles = []string{ - "/etc/ssl/certs/ca-certificates.crt", // Linux etc - "/etc/pki/tls/certs/ca-bundle.crt", // Fedora/RHEL - "/etc/ssl/ca-bundle.pem", // OpenSUSE - "/etc/ssl/cert.pem", // OpenBSD + "/etc/ssl/certs/ca-certificates.crt", // Linux etc + "/etc/pki/tls/certs/ca-bundle.crt", // Fedora/RHEL + "/etc/ssl/ca-bundle.pem", // OpenSUSE + "/etc/ssl/cert.pem", // OpenBSD + "/usr/local/share/certs/ca-root-nss.crt", // FreeBSD } func initDefaultRoots() { diff --git a/libgo/go/crypto/x509/x509.go b/libgo/go/crypto/x509/x509.go index 28c7880..bf39c5d 100644 --- a/libgo/go/crypto/x509/x509.go +++ b/libgo/go/crypto/x509/x509.go @@ -899,6 +899,14 @@ var ( oidRSA = []int{1, 2, 840, 113549, 1, 1, 1} ) +func subjectBytes(cert *Certificate) ([]byte, error) { + if len(cert.RawSubject) > 0 { + return cert.RawSubject, nil + } + + return asn1.Marshal(cert.Subject.ToRDNSequence()) +} + // CreateCertificate creates a new certificate based on a template. The // following members of template are used: SerialNumber, Subject, NotBefore, // NotAfter, KeyUsage, BasicConstraintsValid, IsCA, MaxPathLen, SubjectKeyId, @@ -909,10 +917,23 @@ var ( // signee and priv is the private key of the signer. // // The returned slice is the certificate in DER encoding. -func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.PublicKey, priv *rsa.PrivateKey) (cert []byte, err error) { +// +// The only supported key type is RSA (*rsa.PublicKey for pub, *rsa.PrivateKey +// for priv). +func CreateCertificate(rand io.Reader, template, parent *Certificate, pub interface{}, priv interface{}) (cert []byte, err error) { + rsaPub, ok := pub.(*rsa.PublicKey) + if !ok { + return nil, errors.New("x509: non-RSA public keys not supported") + } + + rsaPriv, ok := priv.(*rsa.PrivateKey) + if !ok { + return nil, errors.New("x509: non-RSA private keys not supported") + } + asn1PublicKey, err := asn1.Marshal(rsaPublicKey{ - N: pub.N, - E: pub.E, + N: rsaPub.N, + E: rsaPub.E, }) if err != nil { return @@ -927,16 +948,12 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.P return } - var asn1Issuer []byte - if len(parent.RawSubject) > 0 { - asn1Issuer = parent.RawSubject - } else { - if asn1Issuer, err = asn1.Marshal(parent.Subject.ToRDNSequence()); err != nil { - return - } + asn1Issuer, err := subjectBytes(parent) + if err != nil { + return } - asn1Subject, err := asn1.Marshal(template.Subject.ToRDNSequence()) + asn1Subject, err := subjectBytes(template) if err != nil { return } @@ -964,7 +981,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.P h.Write(tbsCertContents) digest := h.Sum(nil) - signature, err := rsa.SignPKCS1v15(rand, priv, crypto.SHA1, digest) + signature, err := rsa.SignPKCS1v15(rand, rsaPriv, crypto.SHA1, digest) if err != nil { return } @@ -1011,7 +1028,13 @@ func ParseDERCRL(derBytes []byte) (certList *pkix.CertificateList, err error) { // CreateCRL returns a DER encoded CRL, signed by this Certificate, that // contains the given list of revoked certificates. -func (c *Certificate) CreateCRL(rand io.Reader, priv *rsa.PrivateKey, revokedCerts []pkix.RevokedCertificate, now, expiry time.Time) (crlBytes []byte, err error) { +// +// The only supported key type is RSA (*rsa.PrivateKey for priv). +func (c *Certificate) CreateCRL(rand io.Reader, priv interface{}, revokedCerts []pkix.RevokedCertificate, now, expiry time.Time) (crlBytes []byte, err error) { + rsaPriv, ok := priv.(*rsa.PrivateKey) + if !ok { + return nil, errors.New("x509: non-RSA private keys not supported") + } tbsCertList := pkix.TBSCertificateList{ Version: 2, Signature: pkix.AlgorithmIdentifier{ @@ -1032,7 +1055,7 @@ func (c *Certificate) CreateCRL(rand io.Reader, priv *rsa.PrivateKey, revokedCer h.Write(tbsCertListContents) digest := h.Sum(nil) - signature, err := rsa.SignPKCS1v15(rand, priv, crypto.SHA1, digest) + signature, err := rsa.SignPKCS1v15(rand, rsaPriv, crypto.SHA1, digest) if err != nil { return } diff --git a/libgo/go/database/sql/convert.go b/libgo/go/database/sql/convert.go new file mode 100644 index 0000000..9835e38 --- /dev/null +++ b/libgo/go/database/sql/convert.go @@ -0,0 +1,133 @@ +// 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. + +// Type conversions for Scan. + +package sql + +import ( + "database/sql/driver" + "errors" + "fmt" + "reflect" + "strconv" +) + +// subsetTypeArgs takes a slice of arguments from callers of the sql +// package and converts them into a slice of the driver package's +// "subset types". +func subsetTypeArgs(args []interface{}) ([]interface{}, error) { + out := make([]interface{}, len(args)) + for n, arg := range args { + var err error + out[n], err = driver.DefaultParameterConverter.ConvertValue(arg) + if err != nil { + return nil, fmt.Errorf("sql: converting argument #%d's type: %v", n+1, err) + } + } + return out, nil +} + +// convertAssign copies to dest the value in src, converting it if possible. +// An error is returned if the copy would result in loss of information. +// dest should be a pointer type. +func convertAssign(dest, src interface{}) error { + // Common cases, without reflect. Fall through. + switch s := src.(type) { + case string: + switch d := dest.(type) { + case *string: + *d = s + return nil + } + case []byte: + switch d := dest.(type) { + case *string: + *d = string(s) + return nil + case *[]byte: + *d = s + return nil + } + } + + var sv reflect.Value + + switch d := dest.(type) { + case *string: + sv = reflect.ValueOf(src) + switch sv.Kind() { + case reflect.Bool, + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, + reflect.Float32, reflect.Float64: + *d = fmt.Sprintf("%v", src) + return nil + } + case *bool: + bv, err := driver.Bool.ConvertValue(src) + if err == nil { + *d = bv.(bool) + } + return err + } + + if scanner, ok := dest.(ScannerInto); ok { + return scanner.ScanInto(src) + } + + dpv := reflect.ValueOf(dest) + if dpv.Kind() != reflect.Ptr { + return errors.New("destination not a pointer") + } + + if !sv.IsValid() { + sv = reflect.ValueOf(src) + } + + dv := reflect.Indirect(dpv) + if dv.Kind() == sv.Kind() { + dv.Set(sv) + return nil + } + + switch dv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + s := asString(src) + i64, err := strconv.ParseInt(s, 10, dv.Type().Bits()) + if err != nil { + return fmt.Errorf("converting string %q to a %s: %v", s, dv.Kind(), err) + } + dv.SetInt(i64) + return nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + s := asString(src) + u64, err := strconv.ParseUint(s, 10, dv.Type().Bits()) + if err != nil { + return fmt.Errorf("converting string %q to a %s: %v", s, dv.Kind(), err) + } + dv.SetUint(u64) + return nil + case reflect.Float32, reflect.Float64: + s := asString(src) + f64, err := strconv.ParseFloat(s, dv.Type().Bits()) + if err != nil { + return fmt.Errorf("converting string %q to a %s: %v", s, dv.Kind(), err) + } + dv.SetFloat(f64) + return nil + } + + return fmt.Errorf("unsupported driver -> Scan pair: %T -> %T", src, dest) +} + +func asString(src interface{}) string { + switch v := src.(type) { + case string: + return v + case []byte: + return string(v) + } + return fmt.Sprintf("%v", src) +} diff --git a/libgo/go/database/sql/convert_test.go b/libgo/go/database/sql/convert_test.go new file mode 100644 index 0000000..b188864 --- /dev/null +++ b/libgo/go/database/sql/convert_test.go @@ -0,0 +1,206 @@ +// 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 sql + +import ( + "database/sql/driver" + "fmt" + "reflect" + "testing" + "time" +) + +var someTime = time.Unix(123, 0) + +type conversionTest struct { + s, d interface{} // source and destination + + // following are used if they're non-zero + wantint int64 + wantuint uint64 + wantstr string + wantf32 float32 + wantf64 float64 + wanttime time.Time + wantbool bool // used if d is of type *bool + wanterr string +} + +// Target variables for scanning into. +var ( + scanstr string + scanint int + scanint8 int8 + scanint16 int16 + scanint32 int32 + scanuint8 uint8 + scanuint16 uint16 + scanbool bool + scanf32 float32 + scanf64 float64 + scantime time.Time +) + +var conversionTests = []conversionTest{ + // Exact conversions (destination pointer type matches source type) + {s: "foo", d: &scanstr, wantstr: "foo"}, + {s: 123, d: &scanint, wantint: 123}, + {s: someTime, d: &scantime, wanttime: someTime}, + + // To strings + {s: []byte("byteslice"), d: &scanstr, wantstr: "byteslice"}, + {s: 123, d: &scanstr, wantstr: "123"}, + {s: int8(123), d: &scanstr, wantstr: "123"}, + {s: int64(123), d: &scanstr, wantstr: "123"}, + {s: uint8(123), d: &scanstr, wantstr: "123"}, + {s: uint16(123), d: &scanstr, wantstr: "123"}, + {s: uint32(123), d: &scanstr, wantstr: "123"}, + {s: uint64(123), d: &scanstr, wantstr: "123"}, + {s: 1.5, d: &scanstr, wantstr: "1.5"}, + + // Strings to integers + {s: "255", d: &scanuint8, wantuint: 255}, + {s: "256", d: &scanuint8, wanterr: `converting string "256" to a uint8: strconv.ParseUint: parsing "256": value out of range`}, + {s: "256", d: &scanuint16, wantuint: 256}, + {s: "-1", d: &scanint, wantint: -1}, + {s: "foo", d: &scanint, wanterr: `converting string "foo" to a int: strconv.ParseInt: parsing "foo": invalid syntax`}, + + // True bools + {s: true, d: &scanbool, wantbool: true}, + {s: "True", d: &scanbool, wantbool: true}, + {s: "TRUE", d: &scanbool, wantbool: true}, + {s: "1", d: &scanbool, wantbool: true}, + {s: 1, d: &scanbool, wantbool: true}, + {s: int64(1), d: &scanbool, wantbool: true}, + {s: uint16(1), d: &scanbool, wantbool: true}, + + // False bools + {s: false, d: &scanbool, wantbool: false}, + {s: "false", d: &scanbool, wantbool: false}, + {s: "FALSE", d: &scanbool, wantbool: false}, + {s: "0", d: &scanbool, wantbool: false}, + {s: 0, d: &scanbool, wantbool: false}, + {s: int64(0), d: &scanbool, wantbool: false}, + {s: uint16(0), d: &scanbool, wantbool: false}, + + // Not bools + {s: "yup", d: &scanbool, wanterr: `sql/driver: couldn't convert "yup" into type bool`}, + {s: 2, d: &scanbool, wanterr: `sql/driver: couldn't convert 2 into type bool`}, + + // Floats + {s: float64(1.5), d: &scanf64, wantf64: float64(1.5)}, + {s: int64(1), d: &scanf64, wantf64: float64(1)}, + {s: float64(1.5), d: &scanf32, wantf32: float32(1.5)}, + {s: "1.5", d: &scanf32, wantf32: float32(1.5)}, + {s: "1.5", d: &scanf64, wantf64: float64(1.5)}, +} + +func intValue(intptr interface{}) int64 { + return reflect.Indirect(reflect.ValueOf(intptr)).Int() +} + +func uintValue(intptr interface{}) uint64 { + return reflect.Indirect(reflect.ValueOf(intptr)).Uint() +} + +func float64Value(ptr interface{}) float64 { + return *(ptr.(*float64)) +} + +func float32Value(ptr interface{}) float32 { + return *(ptr.(*float32)) +} + +func timeValue(ptr interface{}) time.Time { + return *(ptr.(*time.Time)) +} + +func TestConversions(t *testing.T) { + for n, ct := range conversionTests { + err := convertAssign(ct.d, ct.s) + errstr := "" + if err != nil { + errstr = err.Error() + } + errf := func(format string, args ...interface{}) { + base := fmt.Sprintf("convertAssign #%d: for %v (%T) -> %T, ", n, ct.s, ct.s, ct.d) + t.Errorf(base+format, args...) + } + if errstr != ct.wanterr { + errf("got error %q, want error %q", errstr, ct.wanterr) + } + if ct.wantstr != "" && ct.wantstr != scanstr { + errf("want string %q, got %q", ct.wantstr, scanstr) + } + if ct.wantint != 0 && ct.wantint != intValue(ct.d) { + errf("want int %d, got %d", ct.wantint, intValue(ct.d)) + } + if ct.wantuint != 0 && ct.wantuint != uintValue(ct.d) { + errf("want uint %d, got %d", ct.wantuint, uintValue(ct.d)) + } + if ct.wantf32 != 0 && ct.wantf32 != float32Value(ct.d) { + errf("want float32 %v, got %v", ct.wantf32, float32Value(ct.d)) + } + if ct.wantf64 != 0 && ct.wantf64 != float64Value(ct.d) { + errf("want float32 %v, got %v", ct.wantf64, float64Value(ct.d)) + } + if bp, boolTest := ct.d.(*bool); boolTest && *bp != ct.wantbool && ct.wanterr == "" { + errf("want bool %v, got %v", ct.wantbool, *bp) + } + if !ct.wanttime.IsZero() && !ct.wanttime.Equal(timeValue(ct.d)) { + errf("want time %v, got %v", ct.wanttime, timeValue(ct.d)) + } + } +} + +func TestNullString(t *testing.T) { + var ns NullString + convertAssign(&ns, []byte("foo")) + if !ns.Valid { + t.Errorf("expecting not null") + } + if ns.String != "foo" { + t.Errorf("expecting foo; got %q", ns.String) + } + convertAssign(&ns, nil) + if ns.Valid { + t.Errorf("expecting null on nil") + } + if ns.String != "" { + t.Errorf("expecting blank on nil; got %q", ns.String) + } +} + +type valueConverterTest struct { + c driver.ValueConverter + in, out interface{} + err string +} + +var valueConverterTests = []valueConverterTest{ + {driver.DefaultParameterConverter, NullString{"hi", true}, "hi", ""}, + {driver.DefaultParameterConverter, NullString{"", false}, nil, ""}, +} + +func TestValueConverters(t *testing.T) { + for i, tt := range valueConverterTests { + out, err := tt.c.ConvertValue(tt.in) + goterr := "" + if err != nil { + goterr = err.Error() + } + if goterr != tt.err { + t.Errorf("test %d: %s(%T(%v)) error = %q; want error = %q", + i, tt.c, tt.in, tt.in, goterr, tt.err) + } + if tt.err != "" { + continue + } + if !reflect.DeepEqual(out, tt.out) { + t.Errorf("test %d: %s(%T(%v)) = %v (%T); want %v (%T)", + i, tt.c, tt.in, tt.in, out, out, tt.out, tt.out) + } + } +} diff --git a/libgo/go/database/sql/driver/driver.go b/libgo/go/database/sql/driver/driver.go new file mode 100644 index 0000000..0cd2562 --- /dev/null +++ b/libgo/go/database/sql/driver/driver.go @@ -0,0 +1,207 @@ +// 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 driver defines interfaces to be implemented by database +// drivers as used by package sql. +// +// Code simply using databases should use package sql. +// +// Drivers only need to be aware of a subset of Go's types. The sql package +// will convert all types into one of the following: +// +// int64 +// float64 +// bool +// nil +// []byte +// string [*] everywhere except from Rows.Next. +// time.Time +// +package driver + +import "errors" + +// Driver is the interface that must be implemented by a database +// driver. +type Driver interface { + // Open returns a new connection to the database. + // The name is a string in a driver-specific format. + // + // Open may return a cached connection (one previously + // closed), but doing so is unnecessary; the sql package + // maintains a pool of idle connections for efficient re-use. + // + // The returned connection is only used by one goroutine at a + // time. + Open(name string) (Conn, error) +} + +// ErrSkip may be returned by some optional interfaces' methods to +// indicate at runtime that the fast path is unavailable and the sql +// package should continue as if the optional interface was not +// implemented. ErrSkip is only supported where explicitly +// documented. +var ErrSkip = errors.New("driver: skip fast-path; continue as if unimplemented") + +// Execer is an optional interface that may be implemented by a Conn. +// +// If a Conn does not implement Execer, the db package's DB.Exec will +// first prepare a query, execute the statement, and then close the +// statement. +// +// All arguments are of a subset type as defined in the package docs. +// +// Exec may return ErrSkip. +type Execer interface { + Exec(query string, args []interface{}) (Result, error) +} + +// Conn is a connection to a database. It is not used concurrently +// by multiple goroutines. +// +// Conn is assumed to be stateful. +type Conn interface { + // Prepare returns a prepared statement, bound to this connection. + Prepare(query string) (Stmt, error) + + // Close invalidates and potentially stops any current + // prepared statements and transactions, marking this + // connection as no longer in use. + // + // Because the sql package maintains a free pool of + // connections and only calls Close when there's a surplus of + // idle connections, it shouldn't be necessary for drivers to + // do their own connection caching. + Close() error + + // Begin starts and returns a new transaction. + Begin() (Tx, error) +} + +// Result is the result of a query execution. +type Result interface { + // LastInsertId returns the database's auto-generated ID + // after, for example, an INSERT into a table with primary + // key. + LastInsertId() (int64, error) + + // RowsAffected returns the number of rows affected by the + // query. + RowsAffected() (int64, error) +} + +// Stmt is a prepared statement. It is bound to a Conn and not +// used by multiple goroutines concurrently. +type Stmt interface { + // Close closes the statement. + // + // Closing a statement should not interrupt any outstanding + // query created from that statement. That is, the following + // order of operations is valid: + // + // * create a driver statement + // * call Query on statement, returning Rows + // * close the statement + // * read from Rows + // + // If closing a statement invalidates currently-running + // queries, the final step above will incorrectly fail. + // + // TODO(bradfitz): possibly remove the restriction above, if + // enough driver authors object and find it complicates their + // code too much. The sql package could be smarter about + // refcounting the statement and closing it at the appropriate + // time. + Close() error + + // NumInput returns the number of placeholder parameters. + // + // If NumInput returns >= 0, the sql package will sanity check + // argument counts from callers and return errors to the caller + // before the statement's Exec or Query methods are called. + // + // NumInput may also return -1, if the driver doesn't know + // its number of placeholders. In that case, the sql package + // will not sanity check Exec or Query argument counts. + NumInput() int + + // Exec executes a query that doesn't return rows, such + // as an INSERT or UPDATE. The args are all of a subset + // type as defined above. + Exec(args []interface{}) (Result, error) + + // Exec executes a query that may return rows, such as a + // SELECT. The args of all of a subset type as defined above. + Query(args []interface{}) (Rows, error) +} + +// ColumnConverter may be optionally implemented by Stmt if the +// the statement is aware of its own columns' types and can +// convert from any type to a driver subset type. +type ColumnConverter interface { + // ColumnConverter returns a ValueConverter for the provided + // column index. If the type of a specific column isn't known + // or shouldn't be handled specially, DefaultValueConverter + // can be returned. + ColumnConverter(idx int) ValueConverter +} + +// Rows is an iterator over an executed query's results. +type Rows interface { + // Columns returns the names of the columns. The number of + // columns of the result is inferred from the length of the + // slice. If a particular column name isn't known, an empty + // string should be returned for that entry. + Columns() []string + + // Close closes the rows iterator. + Close() error + + // Next is called to populate the next row of data into + // the provided slice. The provided slice will be the same + // size as the Columns() are wide. + // + // The dest slice may be populated with only with values + // of subset types defined above, but excluding string. + // All string values must be converted to []byte. + // + // Next should return io.EOF when there are no more rows. + Next(dest []interface{}) error +} + +// Tx is a transaction. +type Tx interface { + Commit() error + Rollback() error +} + +// RowsAffected implements Result for an INSERT or UPDATE operation +// which mutates a number of rows. +type RowsAffected int64 + +var _ Result = RowsAffected(0) + +func (RowsAffected) LastInsertId() (int64, error) { + return 0, errors.New("no LastInsertId available") +} + +func (v RowsAffected) RowsAffected() (int64, error) { + return int64(v), nil +} + +// DDLSuccess is a pre-defined Result for drivers to return when a DDL +// command succeeds. +var DDLSuccess ddlSuccess + +type ddlSuccess struct{} + +var _ Result = ddlSuccess{} + +func (ddlSuccess) LastInsertId() (int64, error) { + return 0, errors.New("no LastInsertId available after DDL statement") +} + +func (ddlSuccess) RowsAffected() (int64, error) { + return 0, errors.New("no RowsAffected available after DDL statement") +} diff --git a/libgo/go/database/sql/driver/types.go b/libgo/go/database/sql/driver/types.go new file mode 100644 index 0000000..f383885 --- /dev/null +++ b/libgo/go/database/sql/driver/types.go @@ -0,0 +1,265 @@ +// 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 driver + +import ( + "fmt" + "reflect" + "strconv" + "time" +) + +// ValueConverter is the interface providing the ConvertValue method. +// +// Various implementations of ValueConverter are provided by the +// driver package to provide consistent implementations of conversions +// between drivers. The ValueConverters have several uses: +// +// * converting from the subset types as provided by the sql package +// into a database table's specific column type and making sure it +// fits, such as making sure a particular int64 fits in a +// table's uint16 column. +// +// * converting a value as given from the database into one of the +// subset types. +// +// * by the sql package, for converting from a driver's subset type +// to a user's type in a scan. +type ValueConverter interface { + // ConvertValue converts a value to a restricted subset type. + ConvertValue(v interface{}) (interface{}, error) +} + +// SubsetValuer is the interface providing the SubsetValue method. +// +// Types implementing SubsetValuer interface are able to convert +// themselves to one of the driver's allowed subset values. +type SubsetValuer interface { + // SubsetValue returns a driver parameter subset value. + SubsetValue() (interface{}, error) +} + +// Bool is a ValueConverter that converts input values to bools. +// +// The conversion rules are: +// - booleans are returned unchanged +// - for integer types, +// 1 is true +// 0 is false, +// other integers are an error +// - for strings and []byte, same rules as strconv.ParseBool +// - all other types are an error +var Bool boolType + +type boolType struct{} + +var _ ValueConverter = boolType{} + +func (boolType) String() string { return "Bool" } + +func (boolType) ConvertValue(src interface{}) (interface{}, error) { + switch s := src.(type) { + case bool: + return s, nil + case string: + b, err := strconv.ParseBool(s) + if err != nil { + return nil, fmt.Errorf("sql/driver: couldn't convert %q into type bool", s) + } + return b, nil + case []byte: + b, err := strconv.ParseBool(string(s)) + if err != nil { + return nil, fmt.Errorf("sql/driver: couldn't convert %q into type bool", s) + } + return b, nil + } + + sv := reflect.ValueOf(src) + switch sv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + iv := sv.Int() + if iv == 1 || iv == 0 { + return iv == 1, nil + } + return nil, fmt.Errorf("sql/driver: couldn't convert %d into type bool", iv) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + uv := sv.Uint() + if uv == 1 || uv == 0 { + return uv == 1, nil + } + return nil, fmt.Errorf("sql/driver: couldn't convert %d into type bool", uv) + } + + return nil, fmt.Errorf("sql/driver: couldn't convert %v (%T) into type bool", src, src) +} + +// Int32 is a ValueConverter that converts input values to int64, +// respecting the limits of an int32 value. +var Int32 int32Type + +type int32Type struct{} + +var _ ValueConverter = int32Type{} + +func (int32Type) ConvertValue(v interface{}) (interface{}, error) { + rv := reflect.ValueOf(v) + switch rv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + i64 := rv.Int() + if i64 > (1<<31)-1 || i64 < -(1<<31) { + return nil, fmt.Errorf("sql/driver: value %d overflows int32", v) + } + return i64, nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + u64 := rv.Uint() + if u64 > (1<<31)-1 { + return nil, fmt.Errorf("sql/driver: value %d overflows int32", v) + } + return int64(u64), nil + case reflect.String: + i, err := strconv.Atoi(rv.String()) + if err != nil { + return nil, fmt.Errorf("sql/driver: value %q can't be converted to int32", v) + } + return int64(i), nil + } + return nil, fmt.Errorf("sql/driver: unsupported value %v (type %T) converting to int32", v, v) +} + +// String is a ValueConverter that converts its input to a string. +// If the value is already a string or []byte, it's unchanged. +// If the value is of another type, conversion to string is done +// with fmt.Sprintf("%v", v). +var String stringType + +type stringType struct{} + +func (stringType) ConvertValue(v interface{}) (interface{}, error) { + switch v.(type) { + case string, []byte: + return v, nil + } + return fmt.Sprintf("%v", v), nil +} + +// Null is a type that implements ValueConverter by allowing nil +// values but otherwise delegating to another ValueConverter. +type Null struct { + Converter ValueConverter +} + +func (n Null) ConvertValue(v interface{}) (interface{}, error) { + if v == nil { + return nil, nil + } + return n.Converter.ConvertValue(v) +} + +// NotNull is a type that implements ValueConverter by disallowing nil +// values but otherwise delegating to another ValueConverter. +type NotNull struct { + Converter ValueConverter +} + +func (n NotNull) ConvertValue(v interface{}) (interface{}, error) { + if v == nil { + return nil, fmt.Errorf("nil value not allowed") + } + return n.Converter.ConvertValue(v) +} + +// IsParameterSubsetType reports whether v is of a valid type for a +// parameter. These types are: +// +// int64 +// float64 +// bool +// nil +// []byte +// time.Time +// string +// +// This is the same list as IsScanSubsetType, with the addition of +// string. +func IsParameterSubsetType(v interface{}) bool { + if IsScanSubsetType(v) { + return true + } + if _, ok := v.(string); ok { + return true + } + return false +} + +// IsScanSubsetType reports whether v is of a valid type for a +// value populated by Rows.Next. These types are: +// +// int64 +// float64 +// bool +// nil +// []byte +// time.Time +// +// This is the same list as IsParameterSubsetType, without string. +func IsScanSubsetType(v interface{}) bool { + if v == nil { + return true + } + switch v.(type) { + case int64, float64, []byte, bool, time.Time: + return true + } + return false +} + +// DefaultParameterConverter is the default implementation of +// ValueConverter that's used when a Stmt doesn't implement +// ColumnConverter. +// +// DefaultParameterConverter returns the given value directly if +// IsSubsetType(value). Otherwise integer type are converted to +// int64, floats to float64, and strings to []byte. Other types are +// an error. +var DefaultParameterConverter defaultConverter + +type defaultConverter struct{} + +var _ ValueConverter = defaultConverter{} + +func (defaultConverter) ConvertValue(v interface{}) (interface{}, error) { + if IsParameterSubsetType(v) { + return v, nil + } + + if svi, ok := v.(SubsetValuer); ok { + sv, err := svi.SubsetValue() + if err != nil { + return nil, err + } + if !IsParameterSubsetType(sv) { + return nil, fmt.Errorf("non-subset type %T returned from SubsetValue", sv) + } + return sv, nil + } + + rv := reflect.ValueOf(v) + switch rv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return rv.Int(), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32: + return int64(rv.Uint()), nil + case reflect.Uint64: + u64 := rv.Uint() + if u64 >= 1<<63 { + return nil, fmt.Errorf("uint64 values with high bit set are not supported") + } + return int64(u64), nil + case reflect.Float32, reflect.Float64: + return rv.Float(), nil + } + return nil, fmt.Errorf("unsupported type %T, a %s", v, rv.Kind()) +} diff --git a/libgo/go/database/sql/driver/types_test.go b/libgo/go/database/sql/driver/types_test.go new file mode 100644 index 0000000..966bc6b --- /dev/null +++ b/libgo/go/database/sql/driver/types_test.go @@ -0,0 +1,61 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package driver + +import ( + "reflect" + "testing" + "time" +) + +type valueConverterTest struct { + c ValueConverter + in interface{} + out interface{} + err string +} + +var now = time.Now() + +var valueConverterTests = []valueConverterTest{ + {Bool, "true", true, ""}, + {Bool, "True", true, ""}, + {Bool, []byte("t"), true, ""}, + {Bool, true, true, ""}, + {Bool, "1", true, ""}, + {Bool, 1, true, ""}, + {Bool, int64(1), true, ""}, + {Bool, uint16(1), true, ""}, + {Bool, "false", false, ""}, + {Bool, false, false, ""}, + {Bool, "0", false, ""}, + {Bool, 0, false, ""}, + {Bool, int64(0), false, ""}, + {Bool, uint16(0), false, ""}, + {c: Bool, in: "foo", err: "sql/driver: couldn't convert \"foo\" into type bool"}, + {c: Bool, in: 2, err: "sql/driver: couldn't convert 2 into type bool"}, + {DefaultParameterConverter, now, now, ""}, +} + +func TestValueConverters(t *testing.T) { + for i, tt := range valueConverterTests { + out, err := tt.c.ConvertValue(tt.in) + goterr := "" + if err != nil { + goterr = err.Error() + } + if goterr != tt.err { + t.Errorf("test %d: %s(%T(%v)) error = %q; want error = %q", + i, tt.c, tt.in, tt.in, goterr, tt.err) + } + if tt.err != "" { + continue + } + if !reflect.DeepEqual(out, tt.out) { + t.Errorf("test %d: %s(%T(%v)) = %v (%T); want %v (%T)", + i, tt.c, tt.in, tt.in, out, out, tt.out, tt.out) + } + } +} diff --git a/libgo/go/database/sql/fakedb_test.go b/libgo/go/database/sql/fakedb_test.go new file mode 100644 index 0000000..b0d137c --- /dev/null +++ b/libgo/go/database/sql/fakedb_test.go @@ -0,0 +1,598 @@ +// 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 sql + +import ( + "database/sql/driver" + "errors" + "fmt" + "io" + "log" + "strconv" + "strings" + "sync" + "time" +) + +var _ = log.Printf + +// fakeDriver is a fake database that implements Go's driver.Driver +// interface, just for testing. +// +// It speaks a query language that's semantically similar to but +// syntantically different and simpler than SQL. The syntax is as +// follows: +// +// WIPE +// CREATE||=,=,... +// where types are: "string", [u]int{8,16,32,64}, "bool" +// INSERT||col=val,col2=val2,col3=? +// SELECT||projectcol1,projectcol2|filtercol=?,filtercol2=? +// +// When opening a a fakeDriver's database, it starts empty with no +// tables. All tables and data are stored in memory only. +type fakeDriver struct { + mu sync.Mutex + openCount int + dbs map[string]*fakeDB +} + +type fakeDB struct { + name string + + mu sync.Mutex + free []*fakeConn + tables map[string]*table +} + +type table struct { + mu sync.Mutex + colname []string + coltype []string + rows []*row +} + +func (t *table) columnIndex(name string) int { + for n, nname := range t.colname { + if name == nname { + return n + } + } + return -1 +} + +type row struct { + cols []interface{} // must be same size as its table colname + coltype +} + +func (r *row) clone() *row { + nrow := &row{cols: make([]interface{}, len(r.cols))} + copy(nrow.cols, r.cols) + return nrow +} + +type fakeConn struct { + db *fakeDB // where to return ourselves to + + currTx *fakeTx + + // Stats for tests: + mu sync.Mutex + stmtsMade int + stmtsClosed int +} + +func (c *fakeConn) incrStat(v *int) { + c.mu.Lock() + *v++ + c.mu.Unlock() +} + +type fakeTx struct { + c *fakeConn +} + +type fakeStmt struct { + c *fakeConn + q string // just for debugging + + cmd string + table string + + closed bool + + colName []string // used by CREATE, INSERT, SELECT (selected columns) + colType []string // used by CREATE + colValue []interface{} // used by INSERT (mix of strings and "?" for bound params) + placeholders int // used by INSERT/SELECT: number of ? params + + whereCol []string // used by SELECT (all placeholders) + + placeholderConverter []driver.ValueConverter // used by INSERT +} + +var fdriver driver.Driver = &fakeDriver{} + +func init() { + Register("test", fdriver) +} + +// Supports dsn forms: +// +// ; (no currently supported options) +func (d *fakeDriver) Open(dsn string) (driver.Conn, error) { + parts := strings.Split(dsn, ";") + if len(parts) < 1 { + return nil, errors.New("fakedb: no database name") + } + name := parts[0] + + db := d.getDB(name) + + d.mu.Lock() + d.openCount++ + d.mu.Unlock() + return &fakeConn{db: db}, nil +} + +func (d *fakeDriver) getDB(name string) *fakeDB { + d.mu.Lock() + defer d.mu.Unlock() + if d.dbs == nil { + d.dbs = make(map[string]*fakeDB) + } + db, ok := d.dbs[name] + if !ok { + db = &fakeDB{name: name} + d.dbs[name] = db + } + return db +} + +func (db *fakeDB) wipe() { + db.mu.Lock() + defer db.mu.Unlock() + db.tables = nil +} + +func (db *fakeDB) createTable(name string, columnNames, columnTypes []string) error { + db.mu.Lock() + defer db.mu.Unlock() + if db.tables == nil { + db.tables = make(map[string]*table) + } + if _, exist := db.tables[name]; exist { + return fmt.Errorf("table %q already exists", name) + } + if len(columnNames) != len(columnTypes) { + return fmt.Errorf("create table of %q len(names) != len(types): %d vs %d", + name, len(columnNames), len(columnTypes)) + } + db.tables[name] = &table{colname: columnNames, coltype: columnTypes} + return nil +} + +// must be called with db.mu lock held +func (db *fakeDB) table(table string) (*table, bool) { + if db.tables == nil { + return nil, false + } + t, ok := db.tables[table] + return t, ok +} + +func (db *fakeDB) columnType(table, column string) (typ string, ok bool) { + db.mu.Lock() + defer db.mu.Unlock() + t, ok := db.table(table) + if !ok { + return + } + for n, cname := range t.colname { + if cname == column { + return t.coltype[n], true + } + } + return "", false +} + +func (c *fakeConn) Begin() (driver.Tx, error) { + if c.currTx != nil { + return nil, errors.New("already in a transaction") + } + c.currTx = &fakeTx{c: c} + return c.currTx, nil +} + +func (c *fakeConn) Close() error { + if c.currTx != nil { + return errors.New("can't close; in a Transaction") + } + if c.db == nil { + return errors.New("can't close; already closed") + } + c.db = nil + return nil +} + +func checkSubsetTypes(args []interface{}) error { + for n, arg := range args { + switch arg.(type) { + case int64, float64, bool, nil, []byte, string, time.Time: + default: + return fmt.Errorf("fakedb_test: invalid argument #%d: %v, type %T", n+1, arg, arg) + } + } + return nil +} + +func (c *fakeConn) Exec(query string, args []interface{}) (driver.Result, error) { + // This is an optional interface, but it's implemented here + // just to check that all the args of of the proper types. + // ErrSkip is returned so the caller acts as if we didn't + // implement this at all. + err := checkSubsetTypes(args) + if err != nil { + return nil, err + } + return nil, driver.ErrSkip +} + +func errf(msg string, args ...interface{}) error { + return errors.New("fakedb: " + fmt.Sprintf(msg, args...)) +} + +// parts are table|selectCol1,selectCol2|whereCol=?,whereCol2=? +// (note that where where columns must always contain ? marks, +// just a limitation for fakedb) +func (c *fakeConn) prepareSelect(stmt *fakeStmt, parts []string) (driver.Stmt, error) { + if len(parts) != 3 { + return nil, errf("invalid SELECT syntax with %d parts; want 3", len(parts)) + } + stmt.table = parts[0] + stmt.colName = strings.Split(parts[1], ",") + for n, colspec := range strings.Split(parts[2], ",") { + if colspec == "" { + continue + } + nameVal := strings.Split(colspec, "=") + if len(nameVal) != 2 { + return nil, errf("SELECT on table %q has invalid column spec of %q (index %d)", stmt.table, colspec, n) + } + column, value := nameVal[0], nameVal[1] + _, ok := c.db.columnType(stmt.table, column) + if !ok { + return nil, errf("SELECT on table %q references non-existent column %q", stmt.table, column) + } + if value != "?" { + return nil, errf("SELECT on table %q has pre-bound value for where column %q; need a question mark", + stmt.table, column) + } + stmt.whereCol = append(stmt.whereCol, column) + stmt.placeholders++ + } + return stmt, nil +} + +// parts are table|col=type,col2=type2 +func (c *fakeConn) prepareCreate(stmt *fakeStmt, parts []string) (driver.Stmt, error) { + if len(parts) != 2 { + return nil, errf("invalid CREATE syntax with %d parts; want 2", len(parts)) + } + stmt.table = parts[0] + for n, colspec := range strings.Split(parts[1], ",") { + nameType := strings.Split(colspec, "=") + if len(nameType) != 2 { + return nil, errf("CREATE table %q has invalid column spec of %q (index %d)", stmt.table, colspec, n) + } + stmt.colName = append(stmt.colName, nameType[0]) + stmt.colType = append(stmt.colType, nameType[1]) + } + return stmt, nil +} + +// parts are table|col=?,col2=val +func (c *fakeConn) prepareInsert(stmt *fakeStmt, parts []string) (driver.Stmt, error) { + if len(parts) != 2 { + return nil, errf("invalid INSERT syntax with %d parts; want 2", len(parts)) + } + stmt.table = parts[0] + for n, colspec := range strings.Split(parts[1], ",") { + nameVal := strings.Split(colspec, "=") + if len(nameVal) != 2 { + return nil, errf("INSERT table %q has invalid column spec of %q (index %d)", stmt.table, colspec, n) + } + column, value := nameVal[0], nameVal[1] + ctype, ok := c.db.columnType(stmt.table, column) + if !ok { + return nil, errf("INSERT table %q references non-existent column %q", stmt.table, column) + } + stmt.colName = append(stmt.colName, column) + + if value != "?" { + var subsetVal interface{} + // Convert to driver subset type + switch ctype { + case "string": + subsetVal = []byte(value) + case "blob": + subsetVal = []byte(value) + case "int32": + i, err := strconv.Atoi(value) + if err != nil { + return nil, errf("invalid conversion to int32 from %q", value) + } + subsetVal = int64(i) // int64 is a subset type, but not int32 + default: + return nil, errf("unsupported conversion for pre-bound parameter %q to type %q", value, ctype) + } + stmt.colValue = append(stmt.colValue, subsetVal) + } else { + stmt.placeholders++ + stmt.placeholderConverter = append(stmt.placeholderConverter, converterForType(ctype)) + stmt.colValue = append(stmt.colValue, "?") + } + } + return stmt, nil +} + +func (c *fakeConn) Prepare(query string) (driver.Stmt, error) { + if c.db == nil { + panic("nil c.db; conn = " + fmt.Sprintf("%#v", c)) + } + parts := strings.Split(query, "|") + if len(parts) < 1 { + return nil, errf("empty query") + } + cmd := parts[0] + parts = parts[1:] + stmt := &fakeStmt{q: query, c: c, cmd: cmd} + c.incrStat(&c.stmtsMade) + switch cmd { + case "WIPE": + // Nothing + case "SELECT": + return c.prepareSelect(stmt, parts) + case "CREATE": + return c.prepareCreate(stmt, parts) + case "INSERT": + return c.prepareInsert(stmt, parts) + default: + return nil, errf("unsupported command type %q", cmd) + } + return stmt, nil +} + +func (s *fakeStmt) ColumnConverter(idx int) driver.ValueConverter { + return s.placeholderConverter[idx] +} + +func (s *fakeStmt) Close() error { + if !s.closed { + s.c.incrStat(&s.c.stmtsClosed) + s.closed = true + } + return nil +} + +var errClosed = errors.New("fakedb: statement has been closed") + +func (s *fakeStmt) Exec(args []interface{}) (driver.Result, error) { + if s.closed { + return nil, errClosed + } + err := checkSubsetTypes(args) + if err != nil { + return nil, err + } + + db := s.c.db + switch s.cmd { + case "WIPE": + db.wipe() + return driver.DDLSuccess, nil + case "CREATE": + if err := db.createTable(s.table, s.colName, s.colType); err != nil { + return nil, err + } + return driver.DDLSuccess, nil + case "INSERT": + return s.execInsert(args) + } + fmt.Printf("EXEC statement, cmd=%q: %#v\n", s.cmd, s) + return nil, fmt.Errorf("unimplemented statement Exec command type of %q", s.cmd) +} + +func (s *fakeStmt) execInsert(args []interface{}) (driver.Result, error) { + db := s.c.db + if len(args) != s.placeholders { + panic("error in pkg db; should only get here if size is correct") + } + db.mu.Lock() + t, ok := db.table(s.table) + db.mu.Unlock() + if !ok { + return nil, fmt.Errorf("fakedb: table %q doesn't exist", s.table) + } + + t.mu.Lock() + defer t.mu.Unlock() + + cols := make([]interface{}, len(t.colname)) + argPos := 0 + for n, colname := range s.colName { + colidx := t.columnIndex(colname) + if colidx == -1 { + return nil, fmt.Errorf("fakedb: column %q doesn't exist or dropped since prepared statement was created", colname) + } + var val interface{} + if strvalue, ok := s.colValue[n].(string); ok && strvalue == "?" { + val = args[argPos] + argPos++ + } else { + val = s.colValue[n] + } + cols[colidx] = val + } + + t.rows = append(t.rows, &row{cols: cols}) + return driver.RowsAffected(1), nil +} + +func (s *fakeStmt) Query(args []interface{}) (driver.Rows, error) { + if s.closed { + return nil, errClosed + } + err := checkSubsetTypes(args) + if err != nil { + return nil, err + } + + db := s.c.db + if len(args) != s.placeholders { + panic("error in pkg db; should only get here if size is correct") + } + + db.mu.Lock() + t, ok := db.table(s.table) + db.mu.Unlock() + if !ok { + return nil, fmt.Errorf("fakedb: table %q doesn't exist", s.table) + } + t.mu.Lock() + defer t.mu.Unlock() + + colIdx := make(map[string]int) // select column name -> column index in table + for _, name := range s.colName { + idx := t.columnIndex(name) + if idx == -1 { + return nil, fmt.Errorf("fakedb: unknown column name %q", name) + } + colIdx[name] = idx + } + + mrows := []*row{} +rows: + for _, trow := range t.rows { + // Process the where clause, skipping non-match rows. This is lazy + // and just uses fmt.Sprintf("%v") to test equality. Good enough + // for test code. + for widx, wcol := range s.whereCol { + idx := t.columnIndex(wcol) + if idx == -1 { + return nil, fmt.Errorf("db: invalid where clause column %q", wcol) + } + tcol := trow.cols[idx] + if bs, ok := tcol.([]byte); ok { + // lazy hack to avoid sprintf %v on a []byte + tcol = string(bs) + } + if fmt.Sprintf("%v", tcol) != fmt.Sprintf("%v", args[widx]) { + continue rows + } + } + mrow := &row{cols: make([]interface{}, len(s.colName))} + for seli, name := range s.colName { + mrow.cols[seli] = trow.cols[colIdx[name]] + } + mrows = append(mrows, mrow) + } + + cursor := &rowsCursor{ + pos: -1, + rows: mrows, + cols: s.colName, + } + return cursor, nil +} + +func (s *fakeStmt) NumInput() int { + return s.placeholders +} + +func (tx *fakeTx) Commit() error { + tx.c.currTx = nil + return nil +} + +func (tx *fakeTx) Rollback() error { + tx.c.currTx = nil + return nil +} + +type rowsCursor struct { + cols []string + pos int + rows []*row + closed bool + + // a clone of slices to give out to clients, indexed by the + // the original slice's first byte address. we clone them + // just so we're able to corrupt them on close. + bytesClone map[*byte][]byte +} + +func (rc *rowsCursor) Close() error { + if !rc.closed { + for _, bs := range rc.bytesClone { + bs[0] = 255 // first byte corrupted + } + } + rc.closed = true + return nil +} + +func (rc *rowsCursor) Columns() []string { + return rc.cols +} + +func (rc *rowsCursor) Next(dest []interface{}) error { + if rc.closed { + return errors.New("fakedb: cursor is closed") + } + rc.pos++ + if rc.pos >= len(rc.rows) { + return io.EOF // per interface spec + } + for i, v := range rc.rows[rc.pos].cols { + // TODO(bradfitz): convert to subset types? naah, I + // think the subset types should only be input to + // driver, but the sql package should be able to handle + // a wider range of types coming out of drivers. all + // for ease of drivers, and to prevent drivers from + // messing up conversions or doing them differently. + dest[i] = v + + if bs, ok := v.([]byte); ok { + if rc.bytesClone == nil { + rc.bytesClone = make(map[*byte][]byte) + } + clone, ok := rc.bytesClone[&bs[0]] + if !ok { + clone = make([]byte, len(bs)) + copy(clone, bs) + rc.bytesClone[&bs[0]] = clone + } + dest[i] = clone + } + } + return nil +} + +func converterForType(typ string) driver.ValueConverter { + switch typ { + case "bool": + return driver.Bool + case "int32": + return driver.Int32 + case "string": + return driver.NotNull{driver.String} + case "nullstring": + return driver.Null{driver.String} + case "datetime": + return driver.DefaultParameterConverter + } + panic("invalid fakedb column type of " + typ) +} diff --git a/libgo/go/database/sql/sql.go b/libgo/go/database/sql/sql.go new file mode 100644 index 0000000..a8bf2a8 --- /dev/null +++ b/libgo/go/database/sql/sql.go @@ -0,0 +1,912 @@ +// 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 sql provides a generic interface around SQL (or SQL-like) +// databases. +package sql + +import ( + "database/sql/driver" + "errors" + "fmt" + "io" + "sync" +) + +var drivers = make(map[string]driver.Driver) + +// Register makes a database driver available by the provided name. +// If Register is called twice with the same name or if driver is nil, +// it panics. +func Register(name string, driver driver.Driver) { + if driver == nil { + panic("sql: Register driver is nil") + } + if _, dup := drivers[name]; dup { + panic("sql: Register called twice for driver " + name) + } + drivers[name] = driver +} + +// RawBytes is a byte slice that holds a reference to memory owned by +// the database itself. After a Scan into a RawBytes, the slice is only +// valid until the next call to Next, Scan, or Close. +type RawBytes []byte + +// NullString represents a string that may be null. +// NullString implements the ScannerInto interface so +// it can be used as a scan destination: +// +// var s NullString +// err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&s) +// ... +// if s.Valid { +// // use s.String +// } else { +// // NULL value +// } +// +// TODO(bradfitz): add other types. +type NullString struct { + String string + Valid bool // Valid is true if String is not NULL +} + +// ScanInto implements the ScannerInto interface. +func (ns *NullString) ScanInto(value interface{}) error { + if value == nil { + ns.String, ns.Valid = "", false + return nil + } + ns.Valid = true + return convertAssign(&ns.String, value) +} + +// SubsetValue implements the driver SubsetValuer interface. +func (ns NullString) SubsetValue() (interface{}, error) { + if !ns.Valid { + return nil, nil + } + return ns.String, nil +} + +// ScannerInto is an interface used by Scan. +type ScannerInto interface { + // ScanInto assigns a value from a database driver. + // + // The value will be of one of the following restricted + // set of types: + // + // int64 + // float64 + // bool + // []byte + // nil - for NULL values + // + // An error should be returned if the value can not be stored + // without loss of information. + ScanInto(value interface{}) error +} + +// 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("sql: no rows in result set") + +// DB is a database handle. It's safe for concurrent use by multiple +// goroutines. +type DB struct { + driver driver.Driver + dsn string + + mu sync.Mutex // protects freeConn and closed + freeConn []driver.Conn + closed bool +} + +// Open opens a database specified by its database driver name and a +// driver-specific data source name, usually consisting of at least a +// database name and connection information. +// +// Most users will open a database via a driver-specific connection +// helper function that returns a *DB. +func Open(driverName, dataSourceName string) (*DB, error) { + driver, ok := drivers[driverName] + if !ok { + return nil, fmt.Errorf("sql: unknown driver %q (forgotten import?)", driverName) + } + return &DB{driver: driver, dsn: dataSourceName}, nil +} + +// Close closes the database, releasing any open resources. +func (db *DB) Close() error { + db.mu.Lock() + defer db.mu.Unlock() + var err error + for _, c := range db.freeConn { + err1 := c.Close() + if err1 != nil { + err = err1 + } + } + db.freeConn = nil + db.closed = true + return err +} + +func (db *DB) maxIdleConns() int { + const defaultMaxIdleConns = 2 + // TODO(bradfitz): ask driver, if supported, for its default preference + // TODO(bradfitz): let users override? + return defaultMaxIdleConns +} + +// conn returns a newly-opened or cached driver.Conn +func (db *DB) conn() (driver.Conn, error) { + db.mu.Lock() + if db.closed { + db.mu.Unlock() + return nil, errors.New("sql: database is closed") + } + if n := len(db.freeConn); n > 0 { + conn := db.freeConn[n-1] + db.freeConn = db.freeConn[:n-1] + db.mu.Unlock() + return conn, nil + } + db.mu.Unlock() + return db.driver.Open(db.dsn) +} + +func (db *DB) connIfFree(wanted driver.Conn) (conn driver.Conn, ok bool) { + db.mu.Lock() + defer db.mu.Unlock() + for n, conn := range db.freeConn { + if conn == wanted { + db.freeConn[n] = db.freeConn[len(db.freeConn)-1] + db.freeConn = db.freeConn[:len(db.freeConn)-1] + return wanted, true + } + } + return nil, false +} + +func (db *DB) putConn(c driver.Conn) { + db.mu.Lock() + defer db.mu.Unlock() + if n := len(db.freeConn); !db.closed && n < db.maxIdleConns() { + db.freeConn = append(db.freeConn, c) + return + } + db.closeConn(c) // TODO(bradfitz): release lock before calling this? +} + +func (db *DB) closeConn(c driver.Conn) { + // TODO: check to see if we need this Conn for any prepared statements + // that are active. + c.Close() +} + +// Prepare creates a prepared statement for later execution. +func (db *DB) Prepare(query string) (*Stmt, error) { + // TODO: check if db.driver supports an optional + // driver.Preparer interface and call that instead, if so, + // otherwise we make a prepared statement that's bound + // to a connection, and to execute this prepared statement + // we either need to use this connection (if it's free), else + // get a new connection + re-prepare + execute on that one. + ci, err := db.conn() + if err != nil { + return nil, err + } + defer db.putConn(ci) + si, err := ci.Prepare(query) + if err != nil { + return nil, err + } + stmt := &Stmt{ + db: db, + query: query, + css: []connStmt{{ci, si}}, + } + return stmt, nil +} + +// Exec executes a query without returning any rows. +func (db *DB) Exec(query string, args ...interface{}) (Result, error) { + sargs, err := subsetTypeArgs(args) + if err != nil { + return nil, err + } + + ci, err := db.conn() + if err != nil { + return nil, err + } + defer db.putConn(ci) + + if execer, ok := ci.(driver.Execer); ok { + resi, err := execer.Exec(query, sargs) + if err != driver.ErrSkip { + if err != nil { + return nil, err + } + return result{resi}, nil + } + } + + sti, err := ci.Prepare(query) + if err != nil { + return nil, err + } + defer sti.Close() + + resi, err := sti.Exec(sargs) + if err != nil { + return nil, err + } + return result{resi}, nil +} + +// Query executes a query that returns rows, typically a SELECT. +func (db *DB) Query(query string, args ...interface{}) (*Rows, error) { + stmt, err := db.Prepare(query) + if err != nil { + return nil, err + } + rows, err := stmt.Query(args...) + if err != nil { + stmt.Close() + return nil, err + } + rows.closeStmt = stmt + return rows, nil +} + +// QueryRow executes a query that is expected to return at most one row. +// QueryRow always return a non-nil value. Errors are deferred until +// Row's Scan method is called. +func (db *DB) QueryRow(query string, args ...interface{}) *Row { + rows, err := db.Query(query, args...) + return &Row{rows: rows, err: err} +} + +// Begin starts a transaction. The isolation level is dependent on +// the driver. +func (db *DB) Begin() (*Tx, error) { + ci, err := db.conn() + if err != nil { + return nil, err + } + txi, err := ci.Begin() + if err != nil { + db.putConn(ci) + return nil, fmt.Errorf("sql: failed to Begin transaction: %v", err) + } + return &Tx{ + db: db, + ci: ci, + txi: txi, + }, nil +} + +// DriverDatabase returns the database's underlying driver. +func (db *DB) Driver() driver.Driver { + return db.driver +} + +// Tx is an in-progress database transaction. +// +// A transaction must end with a call to Commit or Rollback. +// +// After a call to Commit or Rollback, all operations on the +// transaction fail with ErrTransactionFinished. +type Tx struct { + db *DB + + // ci is owned exclusively until Commit or Rollback, at which point + // it's returned with putConn. + ci driver.Conn + txi driver.Tx + + // cimu is held while somebody is using ci (between grabConn + // and releaseConn) + cimu sync.Mutex + + // done transitions from false to true exactly once, on Commit + // or Rollback. once done, all operations fail with + // ErrTransactionFinished. + done bool +} + +var ErrTransactionFinished = errors.New("sql: Transaction has already been committed or rolled back") + +func (tx *Tx) close() { + if tx.done { + panic("double close") // internal error + } + tx.done = true + tx.db.putConn(tx.ci) + tx.ci = nil + tx.txi = nil +} + +func (tx *Tx) grabConn() (driver.Conn, error) { + if tx.done { + return nil, ErrTransactionFinished + } + tx.cimu.Lock() + return tx.ci, nil +} + +func (tx *Tx) releaseConn() { + tx.cimu.Unlock() +} + +// Commit commits the transaction. +func (tx *Tx) Commit() error { + if tx.done { + return ErrTransactionFinished + } + defer tx.close() + return tx.txi.Commit() +} + +// Rollback aborts the transaction. +func (tx *Tx) Rollback() error { + if tx.done { + return ErrTransactionFinished + } + defer tx.close() + return tx.txi.Rollback() +} + +// Prepare creates a prepared statement for use within a transaction. +// +// The returned statement operates within the transaction and can no longer +// be used once the transaction has been committed or rolled back. +// +// To use an existing prepared statement on this transaction, see Tx.Stmt. +func (tx *Tx) Prepare(query string) (*Stmt, error) { + // TODO(bradfitz): We could be more efficient here and either + // provide a method to take an existing Stmt (created on + // perhaps a different Conn), and re-create it on this Conn if + // necessary. Or, better: keep a map in DB of query string to + // Stmts, and have Stmt.Execute do the right thing and + // re-prepare if the Conn in use doesn't have that prepared + // statement. But we'll want to avoid caching the statement + // in the case where we only call conn.Prepare implicitly + // (such as in db.Exec or tx.Exec), but the caller package + // can't be holding a reference to the returned statement. + // Perhaps just looking at the reference count (by noting + // Stmt.Close) would be enough. We might also want a finalizer + // on Stmt to drop the reference count. + ci, err := tx.grabConn() + if err != nil { + return nil, err + } + defer tx.releaseConn() + + si, err := ci.Prepare(query) + if err != nil { + return nil, err + } + + stmt := &Stmt{ + db: tx.db, + tx: tx, + txsi: si, + query: query, + } + return stmt, nil +} + +// Stmt returns a transaction-specific prepared statement from +// an existing statement. +// +// Example: +// updateMoney, err := db.Prepare("UPDATE balance SET money=money+? WHERE id=?") +// ... +// tx, err := db.Begin() +// ... +// res, err := tx.Stmt(updateMoney).Exec(123.45, 98293203) +func (tx *Tx) Stmt(stmt *Stmt) *Stmt { + // TODO(bradfitz): optimize this. Currently this re-prepares + // each time. This is fine for now to illustrate the API but + // we should really cache already-prepared statements + // per-Conn. See also the big comment in Tx.Prepare. + + if tx.db != stmt.db { + return &Stmt{stickyErr: errors.New("sql: Tx.Stmt: statement from different database used")} + } + ci, err := tx.grabConn() + if err != nil { + return &Stmt{stickyErr: err} + } + defer tx.releaseConn() + si, err := ci.Prepare(stmt.query) + return &Stmt{ + db: tx.db, + tx: tx, + txsi: si, + query: stmt.query, + stickyErr: err, + } +} + +// Exec executes a query that doesn't return rows. +// For example: an INSERT and UPDATE. +func (tx *Tx) Exec(query string, args ...interface{}) (Result, error) { + ci, err := tx.grabConn() + if err != nil { + return nil, err + } + defer tx.releaseConn() + + if execer, ok := ci.(driver.Execer); ok { + resi, err := execer.Exec(query, args) + if err != nil { + return nil, err + } + return result{resi}, nil + } + + sti, err := ci.Prepare(query) + if err != nil { + return nil, err + } + defer sti.Close() + + sargs, err := subsetTypeArgs(args) + if err != nil { + return nil, err + } + + resi, err := sti.Exec(sargs) + if err != nil { + return nil, err + } + return result{resi}, nil +} + +// Query executes a query that returns rows, typically a SELECT. +func (tx *Tx) Query(query string, args ...interface{}) (*Rows, error) { + if tx.done { + return nil, ErrTransactionFinished + } + stmt, err := tx.Prepare(query) + if err != nil { + return nil, err + } + defer stmt.Close() + return stmt.Query(args...) +} + +// QueryRow executes a query that is expected to return at most one row. +// QueryRow always return a non-nil value. Errors are deferred until +// Row's Scan method is called. +func (tx *Tx) QueryRow(query string, args ...interface{}) *Row { + rows, err := tx.Query(query, args...) + return &Row{rows: rows, err: err} +} + +// connStmt is a prepared statement on a particular connection. +type connStmt struct { + ci driver.Conn + si driver.Stmt +} + +// Stmt is a prepared statement. Stmt is safe for concurrent use by multiple goroutines. +type Stmt struct { + // Immutable: + db *DB // where we came from + query string // that created the Stmt + stickyErr error // if non-nil, this error is returned for all operations + + // If in a transaction, else both nil: + tx *Tx + txsi driver.Stmt + + mu sync.Mutex // protects the rest of the fields + closed bool + + // css is a list of underlying driver statement interfaces + // that are valid on particular connections. This is only + // used if tx == nil and one is found that has idle + // connections. If tx != nil, txsi is always used. + css []connStmt +} + +// Exec executes a prepared statement with the given arguments and +// returns a Result summarizing the effect of the statement. +func (s *Stmt) Exec(args ...interface{}) (Result, error) { + _, releaseConn, si, err := s.connStmt() + if err != nil { + return nil, err + } + defer releaseConn() + + // -1 means the driver doesn't know how to count the number of + // placeholders, so we won't sanity check input here and instead let the + // driver deal with errors. + if want := si.NumInput(); want != -1 && len(args) != want { + return nil, fmt.Errorf("sql: expected %d arguments, got %d", want, len(args)) + } + + // Convert args to subset types. + if cc, ok := si.(driver.ColumnConverter); ok { + for n, arg := range args { + // First, see if the value itself knows how to convert + // itself to a driver type. For example, a NullString + // struct changing into a string or nil. + if svi, ok := arg.(driver.SubsetValuer); ok { + sv, err := svi.SubsetValue() + if err != nil { + return nil, fmt.Errorf("sql: argument index %d from SubsetValue: %v", n, err) + } + if !driver.IsParameterSubsetType(sv) { + return nil, fmt.Errorf("sql: argument index %d: non-subset type %T returned from SubsetValue", n, sv) + } + arg = sv + } + + // Second, ask the column to sanity check itself. For + // example, drivers might use this to make sure that + // an int64 values being inserted into a 16-bit + // integer field is in range (before getting + // truncated), or that a nil can't go into a NOT NULL + // column before going across the network to get the + // same error. + args[n], err = cc.ColumnConverter(n).ConvertValue(arg) + if err != nil { + return nil, fmt.Errorf("sql: converting Exec argument #%d's type: %v", n, err) + } + if !driver.IsParameterSubsetType(args[n]) { + return nil, fmt.Errorf("sql: driver ColumnConverter error converted %T to unsupported type %T", + arg, args[n]) + } + } + } else { + for n, arg := range args { + args[n], err = driver.DefaultParameterConverter.ConvertValue(arg) + if err != nil { + return nil, fmt.Errorf("sql: converting Exec argument #%d's type: %v", n, err) + } + } + } + + resi, err := si.Exec(args) + if err != nil { + return nil, err + } + return result{resi}, nil +} + +// connStmt returns a free driver connection on which to execute the +// statement, a function to call to release the connection, and a +// statement bound to that connection. +func (s *Stmt) connStmt() (ci driver.Conn, releaseConn func(), si driver.Stmt, err error) { + if err = s.stickyErr; err != nil { + return + } + s.mu.Lock() + if s.closed { + s.mu.Unlock() + err = errors.New("sql: statement is closed") + return + } + + // In a transaction, we always use the connection that the + // transaction was created on. + if s.tx != nil { + s.mu.Unlock() + ci, err = s.tx.grabConn() // blocks, waiting for the connection. + if err != nil { + return + } + releaseConn = func() { s.tx.releaseConn() } + return ci, releaseConn, s.txsi, nil + } + + var cs connStmt + match := false + for _, v := range s.css { + // TODO(bradfitz): lazily clean up entries in this + // list with dead conns while enumerating + if _, match = s.db.connIfFree(cs.ci); match { + cs = v + break + } + } + s.mu.Unlock() + + // Make a new conn if all are busy. + // TODO(bradfitz): or wait for one? make configurable later? + if !match { + ci, err := s.db.conn() + if err != nil { + return nil, nil, nil, err + } + si, err := ci.Prepare(s.query) + if err != nil { + return nil, nil, nil, err + } + s.mu.Lock() + cs = connStmt{ci, si} + s.css = append(s.css, cs) + s.mu.Unlock() + } + + conn := cs.ci + releaseConn = func() { s.db.putConn(conn) } + return conn, releaseConn, cs.si, nil +} + +// Query executes a prepared query statement with the given arguments +// and returns the query results as a *Rows. +func (s *Stmt) Query(args ...interface{}) (*Rows, error) { + ci, releaseConn, si, err := s.connStmt() + if err != nil { + return nil, err + } + + // -1 means the driver doesn't know how to count the number of + // placeholders, so we won't sanity check input here and instead let the + // driver deal with errors. + if want := si.NumInput(); want != -1 && len(args) != want { + return nil, fmt.Errorf("sql: statement expects %d inputs; got %d", si.NumInput(), len(args)) + } + sargs, err := subsetTypeArgs(args) + if err != nil { + return nil, err + } + rowsi, err := si.Query(sargs) + if err != nil { + s.db.putConn(ci) + return nil, err + } + // Note: ownership of ci passes to the *Rows, to be freed + // with releaseConn. + rows := &Rows{ + db: s.db, + ci: ci, + releaseConn: releaseConn, + rowsi: rowsi, + } + return rows, nil +} + +// QueryRow executes a prepared query statement with the given arguments. +// If an error occurs during the execution of the statement, that error will +// be returned by a call to Scan on the returned *Row, which is always non-nil. +// If the query selects no rows, the *Row's Scan will return ErrNoRows. +// Otherwise, the *Row's Scan scans the first selected row and discards +// the rest. +// +// Example usage: +// +// var name string +// err := nameByUseridStmt.QueryRow(id).Scan(&s) +func (s *Stmt) QueryRow(args ...interface{}) *Row { + rows, err := s.Query(args...) + if err != nil { + return &Row{err: err} + } + return &Row{rows: rows} +} + +// Close closes the statement. +func (s *Stmt) Close() error { + if s.stickyErr != nil { + return s.stickyErr + } + s.mu.Lock() + defer s.mu.Unlock() + if s.closed { + return nil + } + s.closed = true + + if s.tx != nil { + s.txsi.Close() + } else { + for _, v := range s.css { + if ci, match := s.db.connIfFree(v.ci); match { + v.si.Close() + s.db.putConn(ci) + } else { + // TODO(bradfitz): care that we can't close + // this statement because the statement's + // connection is in use? + } + } + } + return nil +} + +// Rows is the result of a query. Its cursor starts before the first row +// of the result set. Use Next to advance through the rows: +// +// rows, err := db.Query("SELECT ...") +// ... +// for rows.Next() { +// var id int +// var name string +// err = rows.Scan(&id, &name) +// ... +// } +// err = rows.Err() // get any error encountered during iteration +// ... +type Rows struct { + db *DB + ci driver.Conn // owned; must call putconn when closed to release + releaseConn func() + rowsi driver.Rows + + closed bool + lastcols []interface{} + lasterr error + closeStmt *Stmt // if non-nil, statement to Close on close +} + +// Next prepares the next result row for reading with the Scan method. +// It returns true on success, false if there is no next result row. +// Every call to Scan, even the first one, must be preceded by a call +// to Next. +func (rs *Rows) Next() bool { + if rs.closed { + return false + } + if rs.lasterr != nil { + return false + } + if rs.lastcols == nil { + rs.lastcols = make([]interface{}, len(rs.rowsi.Columns())) + } + rs.lasterr = rs.rowsi.Next(rs.lastcols) + if rs.lasterr == io.EOF { + rs.Close() + } + return rs.lasterr == nil +} + +// Err returns the error, if any, that was encountered during iteration. +func (rs *Rows) Err() error { + if rs.lasterr == io.EOF { + return nil + } + 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 an argument has type *[]byte, Scan saves in that argument a copy +// of the corresponding data. The copy is owned by the caller and can +// be modified and held indefinitely. The copy can be avoided by using +// an argument of type *RawBytes instead; see the documentation for +// RawBytes for restrictions on its use. +func (rs *Rows) Scan(dest ...interface{}) error { + if rs.closed { + return errors.New("sql: Rows closed") + } + if rs.lasterr != nil { + return rs.lasterr + } + if rs.lastcols == nil { + return errors.New("sql: Scan called without calling Next") + } + if len(dest) != len(rs.lastcols) { + 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("sql: Scan error on column index %d: %v", i, err) + } + } + for _, dp := range dest { + b, ok := dp.(*[]byte) + if !ok { + continue + } + if _, ok = dp.(*RawBytes); ok { + continue + } + clone := make([]byte, len(*b)) + copy(clone, *b) + *b = clone + } + return nil +} + +// Close closes the Rows, preventing further enumeration. If the +// end is encountered, the Rows are closed automatically. Close +// is idempotent. +func (rs *Rows) Close() error { + if rs.closed { + return nil + } + rs.closed = true + err := rs.rowsi.Close() + rs.releaseConn() + if rs.closeStmt != nil { + rs.closeStmt.Close() + } + return err +} + +// Row is the result of calling QueryRow to select a single row. +type Row struct { + // One of these two will be non-nil: + err error // deferred error for easy chaining + rows *Rows +} + +// Scan copies the columns from the matched row into the values +// pointed at by dest. If more than one row matches the query, +// Scan uses the first row and discards the rest. If no row matches +// the query, Scan returns ErrNoRows. +func (r *Row) Scan(dest ...interface{}) error { + if r.err != nil { + return r.err + } + defer r.rows.Close() + if !r.rows.Next() { + return ErrNoRows + } + err := r.rows.Scan(dest...) + if err != nil { + return err + } + + // TODO(bradfitz): for now we need to defensively clone all + // []byte that the driver returned, since we're about to close + // the Rows in our defer, when we return from this function. + // the contract with the driver.Next(...) interface is that it + // can return slices into read-only temporary memory that's + // only valid until the next Scan/Close. But the TODO is that + // for a lot of drivers, this copy will be unnecessary. We + // should provide an optional interface for drivers to + // implement to say, "don't worry, the []bytes that I return + // from Next will not be modified again." (for instance, if + // they were obtained from the network anyway) But for now we + // don't care. + for _, dp := range dest { + if _, ok := dp.(*RawBytes); ok { + return errors.New("sql: RawBytes isn't allowed on Row.Scan") + } + b, ok := dp.(*[]byte) + if !ok { + continue + } + clone := make([]byte, len(*b)) + copy(clone, *b) + *b = clone + } + return nil +} + +// A Result summarizes an executed SQL command. +type Result interface { + LastInsertId() (int64, error) + RowsAffected() (int64, error) +} + +type result struct { + driver.Result +} diff --git a/libgo/go/database/sql/sql_test.go b/libgo/go/database/sql/sql_test.go new file mode 100644 index 0000000..3fe9398 --- /dev/null +++ b/libgo/go/database/sql/sql_test.go @@ -0,0 +1,404 @@ +// 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 sql + +import ( + "reflect" + "strings" + "testing" + "time" +) + +const fakeDBName = "foo" + +var chrisBirthday = time.Unix(123456789, 0) + +func newTestDB(t *testing.T, name string) *DB { + db, err := Open("test", fakeDBName) + if err != nil { + t.Fatalf("Open: %v", err) + } + if _, err := db.Exec("WIPE"); err != nil { + t.Fatalf("exec wipe: %v", err) + } + if name == "people" { + exec(t, db, "CREATE|people|name=string,age=int32,photo=blob,dead=bool,bdate=datetime") + exec(t, db, "INSERT|people|name=Alice,age=?,photo=APHOTO", 1) + exec(t, db, "INSERT|people|name=Bob,age=?,photo=BPHOTO", 2) + exec(t, db, "INSERT|people|name=Chris,age=?,photo=CPHOTO,bdate=?", 3, chrisBirthday) + } + return db +} + +func exec(t *testing.T, db *DB, query string, args ...interface{}) { + _, err := db.Exec(query, args...) + if err != nil { + t.Fatalf("Exec of %q: %v", query, err) + } +} + +func closeDB(t *testing.T, db *DB) { + err := db.Close() + if err != nil { + t.Fatalf("error closing DB: %v", err) + } +} + +func TestQuery(t *testing.T) { + db := newTestDB(t, "people") + defer closeDB(t, db) + rows, err := db.Query("SELECT|people|age,name|") + if err != nil { + t.Fatalf("Query: %v", err) + } + type row struct { + age int + name string + } + got := []row{} + for rows.Next() { + var r row + err = rows.Scan(&r.age, &r.name) + if err != nil { + t.Fatalf("Scan: %v", err) + } + got = append(got, r) + } + err = rows.Err() + if err != nil { + t.Fatalf("Err: %v", err) + } + want := []row{ + {age: 1, name: "Alice"}, + {age: 2, name: "Bob"}, + {age: 3, name: "Chris"}, + } + if !reflect.DeepEqual(got, want) { + t.Errorf("mismatch.\n got: %#v\nwant: %#v", got, want) + } + + // And verify that the final rows.Next() call, which hit EOF, + // also closed the rows connection. + if n := len(db.freeConn); n != 1 { + t.Errorf("free conns after query hitting EOF = %d; want 1", n) + } +} + +func TestByteOwnership(t *testing.T) { + db := newTestDB(t, "people") + defer closeDB(t, db) + rows, err := db.Query("SELECT|people|name,photo|") + if err != nil { + t.Fatalf("Query: %v", err) + } + type row struct { + name []byte + photo RawBytes + } + got := []row{} + for rows.Next() { + var r row + err = rows.Scan(&r.name, &r.photo) + if err != nil { + t.Fatalf("Scan: %v", err) + } + got = append(got, r) + } + corruptMemory := []byte("\xffPHOTO") + want := []row{ + {name: []byte("Alice"), photo: corruptMemory}, + {name: []byte("Bob"), photo: corruptMemory}, + {name: []byte("Chris"), photo: corruptMemory}, + } + if !reflect.DeepEqual(got, want) { + t.Errorf("mismatch.\n got: %#v\nwant: %#v", got, want) + } + + var photo RawBytes + err = db.QueryRow("SELECT|people|photo|name=?", "Alice").Scan(&photo) + if err == nil { + t.Error("want error scanning into RawBytes from QueryRow") + } +} + +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) + var name string + var age int + var birthday time.Time + + err := db.QueryRow("SELECT|people|age,name|age=?", 3).Scan(&age) + if err == nil || !strings.Contains(err.Error(), "expected 2 destination arguments") { + t.Errorf("expected error from wrong number of arguments; actually got: %v", err) + } + + err = db.QueryRow("SELECT|people|bdate|age=?", 3).Scan(&birthday) + if err != nil || !birthday.Equal(chrisBirthday) { + t.Errorf("chris birthday = %v, err = %v; want %v", birthday, err, chrisBirthday) + } + + err = db.QueryRow("SELECT|people|age,name|age=?", 2).Scan(&age, &name) + if err != nil { + t.Fatalf("age QueryRow+Scan: %v", err) + } + if name != "Bob" { + t.Errorf("expected name Bob, got %q", name) + } + if age != 2 { + t.Errorf("expected age 2, got %d", age) + } + + err = db.QueryRow("SELECT|people|age,name|name=?", "Alice").Scan(&age, &name) + if err != nil { + t.Fatalf("name QueryRow+Scan: %v", err) + } + if name != "Alice" { + t.Errorf("expected name Alice, got %q", name) + } + if age != 1 { + t.Errorf("expected age 1, got %d", age) + } + + var photo []byte + err = db.QueryRow("SELECT|people|photo|name=?", "Alice").Scan(&photo) + if err != nil { + t.Fatalf("photo QueryRow+Scan: %v", err) + } + want := []byte("APHOTO") + if !reflect.DeepEqual(photo, want) { + t.Errorf("photo = %q; want %q", photo, want) + } +} + +func TestStatementErrorAfterClose(t *testing.T) { + db := newTestDB(t, "people") + defer closeDB(t, db) + stmt, err := db.Prepare("SELECT|people|age|name=?") + if err != nil { + t.Fatalf("Prepare: %v", err) + } + err = stmt.Close() + if err != nil { + t.Fatalf("Close: %v", err) + } + var name string + err = stmt.QueryRow("foo").Scan(&name) + if err == nil { + t.Errorf("expected error from QueryRow.Scan after Stmt.Close") + } +} + +func TestStatementQueryRow(t *testing.T) { + db := newTestDB(t, "people") + defer closeDB(t, db) + stmt, err := db.Prepare("SELECT|people|age|name=?") + if err != nil { + t.Fatalf("Prepare: %v", err) + } + var age int + for n, tt := range []struct { + name string + want int + }{ + {"Alice", 1}, + {"Bob", 2}, + {"Chris", 3}, + } { + if err := stmt.QueryRow(tt.name).Scan(&age); err != nil { + t.Errorf("%d: on %q, QueryRow/Scan: %v", n, tt.name, err) + } else if age != tt.want { + t.Errorf("%d: age=%d, want %d", n, age, tt.want) + } + } + +} + +// just a test of fakedb itself +func TestBogusPreboundParameters(t *testing.T) { + db := newTestDB(t, "foo") + defer closeDB(t, db) + exec(t, db, "CREATE|t1|name=string,age=int32,dead=bool") + _, err := db.Prepare("INSERT|t1|name=?,age=bogusconversion") + if err == nil { + t.Fatalf("expected error") + } + if err.Error() != `fakedb: invalid conversion to int32 from "bogusconversion"` { + t.Errorf("unexpected error: %v", err) + } +} + +func TestExec(t *testing.T) { + db := newTestDB(t, "foo") + defer closeDB(t, db) + exec(t, db, "CREATE|t1|name=string,age=int32,dead=bool") + stmt, err := db.Prepare("INSERT|t1|name=?,age=?") + if err != nil { + t.Errorf("Stmt, err = %v, %v", stmt, err) + } + + type execTest struct { + args []interface{} + wantErr string + } + execTests := []execTest{ + // Okay: + {[]interface{}{"Brad", 31}, ""}, + {[]interface{}{"Brad", int64(31)}, ""}, + {[]interface{}{"Bob", "32"}, ""}, + {[]interface{}{7, 9}, ""}, + + // Invalid conversions: + {[]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{}{}, "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...) + errStr := "" + if err != nil { + errStr = err.Error() + } + if errStr != et.wantErr { + t.Errorf("stmt.Execute #%d: for %v, got error %q, want error %q", + n, et.args, errStr, et.wantErr) + } + } +} + +func TestTxStmt(t *testing.T) { + db := newTestDB(t, "") + defer closeDB(t, db) + exec(t, db, "CREATE|t1|name=string,age=int32,dead=bool") + stmt, err := db.Prepare("INSERT|t1|name=?,age=?") + if err != nil { + t.Fatalf("Stmt, err = %v, %v", stmt, err) + } + tx, err := db.Begin() + if err != nil { + t.Fatalf("Begin = %v", err) + } + _, err = tx.Stmt(stmt).Exec("Bobby", 7) + if err != nil { + t.Fatalf("Exec = %v", err) + } + err = tx.Commit() + if err != nil { + t.Fatalf("Commit = %v", err) + } +} + +// Tests fix for issue 2542, that we release a lock when querying on +// a closed connection. +func TestIssue2542Deadlock(t *testing.T) { + db := newTestDB(t, "people") + closeDB(t, db) + for i := 0; i < 2; i++ { + _, err := db.Query("SELECT|people|age,name|") + if err == nil { + t.Fatalf("expected error") + } + } +} + +func TestQueryRowClosingStmt(t *testing.T) { + db := newTestDB(t, "people") + defer closeDB(t, db) + var name string + var age int + err := db.QueryRow("SELECT|people|age,name|age=?", 3).Scan(&age, &name) + if err != nil { + t.Fatal(err) + } + if len(db.freeConn) != 1 { + t.Fatalf("expected 1 free conn") + } + fakeConn := db.freeConn[0].(*fakeConn) + if made, closed := fakeConn.stmtsMade, fakeConn.stmtsClosed; made != closed { + t.Errorf("statement close mismatch: made %d, closed %d", made, closed) + } +} + +func TestNullStringParam(t *testing.T) { + db := newTestDB(t, "") + defer closeDB(t, db) + exec(t, db, "CREATE|t|id=int32,name=string,favcolor=nullstring") + + // Inserts with db.Exec: + exec(t, db, "INSERT|t|id=?,name=?,favcolor=?", 1, "alice", NullString{"aqua", true}) + exec(t, db, "INSERT|t|id=?,name=?,favcolor=?", 2, "bob", NullString{"brown", false}) + + _, err := db.Exec("INSERT|t|id=?,name=?,favcolor=?", 999, nil, nil) + if err == nil { + // TODO: this test fails, but it's just because + // fakeConn implements the optional Execer interface, + // so arguably this is the correct behavior. But + // maybe I should flesh out the fakeConn.Exec + // implementation so this properly fails. + // t.Errorf("expected error inserting nil name with Exec") + } + + // Inserts with a prepared statement: + stmt, err := db.Prepare("INSERT|t|id=?,name=?,favcolor=?") + if err != nil { + t.Fatalf("prepare: %v", err) + } + if _, err := stmt.Exec(3, "chris", "chartreuse"); err != nil { + t.Errorf("exec insert chris: %v", err) + } + if _, err := stmt.Exec(4, "dave", NullString{"darkred", true}); err != nil { + t.Errorf("exec insert dave: %v", err) + } + if _, err := stmt.Exec(5, "eleanor", NullString{"eel", false}); err != nil { + t.Errorf("exec insert dave: %v", err) + } + + // Can't put null name into non-nullstring column, + if _, err := stmt.Exec(5, NullString{"", false}, nil); err == nil { + t.Errorf("expected error inserting nil name with prepared statement Exec") + } + + type nameColor struct { + name string + favColor NullString + } + + wantMap := map[int]nameColor{ + 1: nameColor{"alice", NullString{"aqua", true}}, + 2: nameColor{"bob", NullString{"", false}}, + 3: nameColor{"chris", NullString{"chartreuse", true}}, + 4: nameColor{"dave", NullString{"darkred", true}}, + 5: nameColor{"eleanor", NullString{"", false}}, + } + for id, want := range wantMap { + var got nameColor + if err := db.QueryRow("SELECT|t|name,favcolor|id=?", id).Scan(&got.name, &got.favColor); err != nil { + t.Errorf("id=%d Scan: %v", id, err) + } + if got != want { + t.Errorf("id=%d got %#v, want %#v", id, got, want) + } + } +} diff --git a/libgo/go/encoding/gob/debug.go b/libgo/go/encoding/gob/debug.go index b21c7fa..4a61d0f 100644 --- a/libgo/go/encoding/gob/debug.go +++ b/libgo/go/encoding/gob/debug.go @@ -1,3 +1,7 @@ +// 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 gob // This file is not normally included in the gob package. Used only for debugging the package itself. diff --git a/libgo/go/encoding/gob/dump.go b/libgo/go/encoding/gob/dump.go index 0d0017c..f7d822c 100644 --- a/libgo/go/encoding/gob/dump.go +++ b/libgo/go/encoding/gob/dump.go @@ -1,3 +1,7 @@ +// 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 main // Need to compile package gob with debug.go to build this program. diff --git a/libgo/go/encoding/json/encode.go b/libgo/go/encoding/json/encode.go index 033da2d..eac14a4 100644 --- a/libgo/go/encoding/json/encode.go +++ b/libgo/go/encoding/json/encode.go @@ -39,6 +39,8 @@ import ( // // String values encode as JSON strings, with each invalid UTF-8 sequence // replaced by the encoding of the Unicode replacement character U+FFFD. +// The angle brackets "<" and ">" are escaped to "\u003c" and "\u003e" +// to keep some browsers from misinterpreting JSON output as HTML. // // Array and slice values encode as JSON arrays, except that // []byte encodes as a base64-encoded string. @@ -77,7 +79,8 @@ import ( // Int64String int64 `json:",string"` // // The key name will be used if it's a non-empty string consisting of -// only Unicode letters, digits, dollar signs, hyphens, and underscores. +// only Unicode letters, digits, dollar signs, percent signs, hyphens, +// underscores and slashes. // // Map values encode as JSON objects. // The map's key type must be string; the object keys are used directly @@ -417,8 +420,13 @@ func isValidTag(s string) bool { return false } for _, c := range s { - if c != '$' && c != '-' && c != '_' && !unicode.IsLetter(c) && !unicode.IsDigit(c) { - return false + switch c { + case '$', '-', '_', '/', '%': + // Acceptable + default: + if !unicode.IsLetter(c) && !unicode.IsDigit(c) { + return false + } } } return true diff --git a/libgo/go/encoding/json/tagkey_test.go b/libgo/go/encoding/json/tagkey_test.go index 31fe2be..bba5730 100644 --- a/libgo/go/encoding/json/tagkey_test.go +++ b/libgo/go/encoding/json/tagkey_test.go @@ -9,7 +9,7 @@ import ( ) type basicLatin2xTag struct { - V string `json:"$-"` + V string `json:"$%-/"` } type basicLatin3xTag struct { @@ -36,6 +36,10 @@ type miscPlaneTag struct { V string `json:"色は匂へど"` } +type percentSlashTag struct { + V string `json:"text/html%"` // http://golang.org/issue/2718 +} + type emptyTag struct { W string } @@ -49,7 +53,7 @@ type badFormatTag struct { } type badCodeTag struct { - Z string `json:" !\"#%&'()*+,./"` + Z string `json:" !\"#&'()*+,."` } var structTagObjectKeyTests = []struct { @@ -57,7 +61,7 @@ var structTagObjectKeyTests = []struct { value string key string }{ - {basicLatin2xTag{"2x"}, "2x", "$-"}, + {basicLatin2xTag{"2x"}, "2x", "$%-/"}, {basicLatin3xTag{"3x"}, "3x", "0123456789"}, {basicLatin4xTag{"4x"}, "4x", "ABCDEFGHIJKLMO"}, {basicLatin5xTag{"5x"}, "5x", "PQRSTUVWXYZ_"}, @@ -68,6 +72,7 @@ var structTagObjectKeyTests = []struct { {misnamedTag{"Animal Kingdom"}, "Animal Kingdom", "X"}, {badFormatTag{"Orfevre"}, "Orfevre", "Y"}, {badCodeTag{"Reliable Man"}, "Reliable Man", "Z"}, + {percentSlashTag{"brut"}, "brut", "text/html%"}, } func TestStructTagObjectKey(t *testing.T) { @@ -88,7 +93,7 @@ func TestStructTagObjectKey(t *testing.T) { t.Fatalf("Unexpected value: %#q, want %v", s, tt.value) } default: - t.Fatalf("Unexpected key: %#q", i) + t.Fatalf("Unexpected key: %#q, from %#q", i, b) } } } diff --git a/libgo/go/encoding/xml/marshal_test.go b/libgo/go/encoding/xml/marshal_test.go index bec5376..f23b2cb 100644 --- a/libgo/go/encoding/xml/marshal_test.go +++ b/libgo/go/encoding/xml/marshal_test.go @@ -150,6 +150,10 @@ type XMLNameWithoutTag struct { Value string ",chardata" } +type NameInField struct { + Foo Name `xml:"ns foo"` +} + type AttrTest struct { Int int `xml:",attr"` Lower int `xml:"int,attr"` @@ -483,6 +487,19 @@ var marshalTests = []struct { UnmarshalOnly: true, }, + // xml.Name works in a plain field as well. + { + Value: &NameInField{Name{Space: "ns", Local: "foo"}}, + ExpectXML: ``, + }, + + // Marshaling zero xml.Name uses the tag or field name. + { + Value: &NameInField{}, + ExpectXML: ``, + MarshalOnly: true, + }, + // Test attributes { Value: &AttrTest{ diff --git a/libgo/go/encoding/xml/read.go b/libgo/go/encoding/xml/read.go index dde68de..4419ed1 100644 --- a/libgo/go/encoding/xml/read.go +++ b/libgo/go/encoding/xml/read.go @@ -271,6 +271,10 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) error { case reflect.Struct: sv = v typ := sv.Type() + if typ == nameType { + v.Set(reflect.ValueOf(start.Name)) + break + } tinfo, err = getTypeInfo(typ) if err != nil { return err diff --git a/libgo/go/encoding/xml/typeinfo.go b/libgo/go/encoding/xml/typeinfo.go index 8f79c4e..36b35ed 100644 --- a/libgo/go/encoding/xml/typeinfo.go +++ b/libgo/go/encoding/xml/typeinfo.go @@ -46,6 +46,8 @@ const ( var tinfoMap = make(map[reflect.Type]*typeInfo) var tinfoLock sync.RWMutex +var nameType = reflect.TypeOf(Name{}) + // getTypeInfo returns the typeInfo structure with details necessary // for marshalling and unmarshalling typ. func getTypeInfo(typ reflect.Type) (*typeInfo, error) { @@ -56,7 +58,7 @@ func getTypeInfo(typ reflect.Type) (*typeInfo, error) { return tinfo, nil } tinfo = &typeInfo{} - if typ.Kind() == reflect.Struct { + if typ.Kind() == reflect.Struct && typ != nameType { n := typ.NumField() for i := 0; i < n; i++ { f := typ.Field(i) diff --git a/libgo/go/exp/gotype/testdata/test1.go b/libgo/go/exp/gotype/testdata/test1.go index a3298e6..ba8a51f 100644 --- a/libgo/go/exp/gotype/testdata/test1.go +++ b/libgo/go/exp/gotype/testdata/test1.go @@ -1,3 +1,7 @@ +// 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 p func _() { diff --git a/libgo/go/exp/inotify/inotify_linux_test.go b/libgo/go/exp/inotify/inotify_linux_test.go index d035ec1..c2160fc 100644 --- a/libgo/go/exp/inotify/inotify_linux_test.go +++ b/libgo/go/exp/inotify/inotify_linux_test.go @@ -83,14 +83,15 @@ func TestInotifyClose(t *testing.T) { watcher, _ := NewWatcher() watcher.Close() - done := false + done := make(chan bool) go func() { watcher.Close() - done = true + done <- true }() - time.Sleep(50 * time.Millisecond) - if !done { + select { + case <-done: + case <-time.After(50 * time.Millisecond): t.Fatal("double Close() test failed: second Close() call didn't return") } diff --git a/libgo/go/exp/norm/trie_test.go b/libgo/go/exp/norm/trie_test.go index 7308d28..c457c9d 100644 --- a/libgo/go/exp/norm/trie_test.go +++ b/libgo/go/exp/norm/trie_test.go @@ -1,3 +1,7 @@ +// 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 norm import ( diff --git a/libgo/go/exp/proxy/proxy.go b/libgo/go/exp/proxy/proxy.go index ccd3d1d..b6cfd45 100644 --- a/libgo/go/exp/proxy/proxy.go +++ b/libgo/go/exp/proxy/proxy.go @@ -11,7 +11,6 @@ import ( "net" "net/url" "os" - "strings" ) // A Dialer is a means to establish a connection. @@ -70,14 +69,11 @@ func RegisterDialerType(scheme string, f func(*url.URL, Dialer) (Dialer, error)) // Dialer for it to make network requests. func FromURL(u *url.URL, forward Dialer) (Dialer, error) { var auth *Auth - if len(u.RawUserinfo) > 0 { + if u.User != nil { auth = new(Auth) - parts := strings.SplitN(u.RawUserinfo, ":", 1) - if len(parts) == 1 { - auth.User = parts[0] - } else if len(parts) >= 2 { - auth.User = parts[0] - auth.Password = parts[1] + auth.User = u.User.Username() + if p, ok := u.User.Password(); ok { + auth.Password = p } } diff --git a/libgo/go/exp/sql/convert.go b/libgo/go/exp/sql/convert.go deleted file mode 100644 index feb79ae..0000000 --- a/libgo/go/exp/sql/convert.go +++ /dev/null @@ -1,133 +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. - -// Type conversions for Scan. - -package sql - -import ( - "errors" - "exp/sql/driver" - "fmt" - "reflect" - "strconv" -) - -// subsetTypeArgs takes a slice of arguments from callers of the sql -// package and converts them into a slice of the driver package's -// "subset types". -func subsetTypeArgs(args []interface{}) ([]interface{}, error) { - out := make([]interface{}, len(args)) - for n, arg := range args { - var err error - out[n], err = driver.DefaultParameterConverter.ConvertValue(arg) - if err != nil { - return nil, fmt.Errorf("sql: converting argument #%d's type: %v", n+1, err) - } - } - return out, nil -} - -// convertAssign copies to dest the value in src, converting it if possible. -// An error is returned if the copy would result in loss of information. -// dest should be a pointer type. -func convertAssign(dest, src interface{}) error { - // Common cases, without reflect. Fall through. - switch s := src.(type) { - case string: - switch d := dest.(type) { - case *string: - *d = s - return nil - } - case []byte: - switch d := dest.(type) { - case *string: - *d = string(s) - return nil - case *[]byte: - *d = s - return nil - } - } - - var sv reflect.Value - - switch d := dest.(type) { - case *string: - sv = reflect.ValueOf(src) - switch sv.Kind() { - case reflect.Bool, - reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, - reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, - reflect.Float32, reflect.Float64: - *d = fmt.Sprintf("%v", src) - return nil - } - case *bool: - bv, err := driver.Bool.ConvertValue(src) - if err == nil { - *d = bv.(bool) - } - return err - } - - if scanner, ok := dest.(ScannerInto); ok { - return scanner.ScanInto(src) - } - - dpv := reflect.ValueOf(dest) - if dpv.Kind() != reflect.Ptr { - return errors.New("destination not a pointer") - } - - if !sv.IsValid() { - sv = reflect.ValueOf(src) - } - - dv := reflect.Indirect(dpv) - if dv.Kind() == sv.Kind() { - dv.Set(sv) - return nil - } - - switch dv.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - s := asString(src) - i64, err := strconv.ParseInt(s, 10, dv.Type().Bits()) - if err != nil { - return fmt.Errorf("converting string %q to a %s: %v", s, dv.Kind(), err) - } - dv.SetInt(i64) - return nil - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - s := asString(src) - u64, err := strconv.ParseUint(s, 10, dv.Type().Bits()) - if err != nil { - return fmt.Errorf("converting string %q to a %s: %v", s, dv.Kind(), err) - } - dv.SetUint(u64) - return nil - case reflect.Float32, reflect.Float64: - s := asString(src) - f64, err := strconv.ParseFloat(s, dv.Type().Bits()) - if err != nil { - return fmt.Errorf("converting string %q to a %s: %v", s, dv.Kind(), err) - } - dv.SetFloat(f64) - return nil - } - - return fmt.Errorf("unsupported driver -> Scan pair: %T -> %T", src, dest) -} - -func asString(src interface{}) string { - switch v := src.(type) { - case string: - return v - case []byte: - return string(v) - } - return fmt.Sprintf("%v", src) -} diff --git a/libgo/go/exp/sql/convert_test.go b/libgo/go/exp/sql/convert_test.go deleted file mode 100644 index 702ba43..0000000 --- a/libgo/go/exp/sql/convert_test.go +++ /dev/null @@ -1,173 +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 sql - -import ( - "fmt" - "reflect" - "testing" - "time" -) - -var someTime = time.Unix(123, 0) - -type conversionTest struct { - s, d interface{} // source and destination - - // following are used if they're non-zero - wantint int64 - wantuint uint64 - wantstr string - wantf32 float32 - wantf64 float64 - wanttime time.Time - wantbool bool // used if d is of type *bool - wanterr string -} - -// Target variables for scanning into. -var ( - scanstr string - scanint int - scanint8 int8 - scanint16 int16 - scanint32 int32 - scanuint8 uint8 - scanuint16 uint16 - scanbool bool - scanf32 float32 - scanf64 float64 - scantime time.Time -) - -var conversionTests = []conversionTest{ - // Exact conversions (destination pointer type matches source type) - {s: "foo", d: &scanstr, wantstr: "foo"}, - {s: 123, d: &scanint, wantint: 123}, - {s: someTime, d: &scantime, wanttime: someTime}, - - // To strings - {s: []byte("byteslice"), d: &scanstr, wantstr: "byteslice"}, - {s: 123, d: &scanstr, wantstr: "123"}, - {s: int8(123), d: &scanstr, wantstr: "123"}, - {s: int64(123), d: &scanstr, wantstr: "123"}, - {s: uint8(123), d: &scanstr, wantstr: "123"}, - {s: uint16(123), d: &scanstr, wantstr: "123"}, - {s: uint32(123), d: &scanstr, wantstr: "123"}, - {s: uint64(123), d: &scanstr, wantstr: "123"}, - {s: 1.5, d: &scanstr, wantstr: "1.5"}, - - // Strings to integers - {s: "255", d: &scanuint8, wantuint: 255}, - {s: "256", d: &scanuint8, wanterr: `converting string "256" to a uint8: strconv.ParseUint: parsing "256": value out of range`}, - {s: "256", d: &scanuint16, wantuint: 256}, - {s: "-1", d: &scanint, wantint: -1}, - {s: "foo", d: &scanint, wanterr: `converting string "foo" to a int: strconv.ParseInt: parsing "foo": invalid syntax`}, - - // True bools - {s: true, d: &scanbool, wantbool: true}, - {s: "True", d: &scanbool, wantbool: true}, - {s: "TRUE", d: &scanbool, wantbool: true}, - {s: "1", d: &scanbool, wantbool: true}, - {s: 1, d: &scanbool, wantbool: true}, - {s: int64(1), d: &scanbool, wantbool: true}, - {s: uint16(1), d: &scanbool, wantbool: true}, - - // False bools - {s: false, d: &scanbool, wantbool: false}, - {s: "false", d: &scanbool, wantbool: false}, - {s: "FALSE", d: &scanbool, wantbool: false}, - {s: "0", d: &scanbool, wantbool: false}, - {s: 0, d: &scanbool, wantbool: false}, - {s: int64(0), d: &scanbool, wantbool: false}, - {s: uint16(0), d: &scanbool, wantbool: false}, - - // Not bools - {s: "yup", d: &scanbool, wanterr: `sql/driver: couldn't convert "yup" into type bool`}, - {s: 2, d: &scanbool, wanterr: `sql/driver: couldn't convert 2 into type bool`}, - - // Floats - {s: float64(1.5), d: &scanf64, wantf64: float64(1.5)}, - {s: int64(1), d: &scanf64, wantf64: float64(1)}, - {s: float64(1.5), d: &scanf32, wantf32: float32(1.5)}, - {s: "1.5", d: &scanf32, wantf32: float32(1.5)}, - {s: "1.5", d: &scanf64, wantf64: float64(1.5)}, -} - -func intValue(intptr interface{}) int64 { - return reflect.Indirect(reflect.ValueOf(intptr)).Int() -} - -func uintValue(intptr interface{}) uint64 { - return reflect.Indirect(reflect.ValueOf(intptr)).Uint() -} - -func float64Value(ptr interface{}) float64 { - return *(ptr.(*float64)) -} - -func float32Value(ptr interface{}) float32 { - return *(ptr.(*float32)) -} - -func timeValue(ptr interface{}) time.Time { - return *(ptr.(*time.Time)) -} - -func TestConversions(t *testing.T) { - for n, ct := range conversionTests { - err := convertAssign(ct.d, ct.s) - errstr := "" - if err != nil { - errstr = err.Error() - } - errf := func(format string, args ...interface{}) { - base := fmt.Sprintf("convertAssign #%d: for %v (%T) -> %T, ", n, ct.s, ct.s, ct.d) - t.Errorf(base+format, args...) - } - if errstr != ct.wanterr { - errf("got error %q, want error %q", errstr, ct.wanterr) - } - if ct.wantstr != "" && ct.wantstr != scanstr { - errf("want string %q, got %q", ct.wantstr, scanstr) - } - if ct.wantint != 0 && ct.wantint != intValue(ct.d) { - errf("want int %d, got %d", ct.wantint, intValue(ct.d)) - } - if ct.wantuint != 0 && ct.wantuint != uintValue(ct.d) { - errf("want uint %d, got %d", ct.wantuint, uintValue(ct.d)) - } - if ct.wantf32 != 0 && ct.wantf32 != float32Value(ct.d) { - errf("want float32 %v, got %v", ct.wantf32, float32Value(ct.d)) - } - if ct.wantf64 != 0 && ct.wantf64 != float64Value(ct.d) { - errf("want float32 %v, got %v", ct.wantf64, float64Value(ct.d)) - } - if bp, boolTest := ct.d.(*bool); boolTest && *bp != ct.wantbool && ct.wanterr == "" { - errf("want bool %v, got %v", ct.wantbool, *bp) - } - if !ct.wanttime.IsZero() && !ct.wanttime.Equal(timeValue(ct.d)) { - errf("want time %v, got %v", ct.wanttime, timeValue(ct.d)) - } - } -} - -func TestNullableString(t *testing.T) { - var ns NullableString - convertAssign(&ns, []byte("foo")) - if !ns.Valid { - t.Errorf("expecting not null") - } - if ns.String != "foo" { - t.Errorf("expecting foo; got %q", ns.String) - } - convertAssign(&ns, nil) - if ns.Valid { - t.Errorf("expecting null on nil") - } - if ns.String != "" { - t.Errorf("expecting blank on nil; got %q", ns.String) - } -} diff --git a/libgo/go/exp/sql/driver/driver.go b/libgo/go/exp/sql/driver/driver.go deleted file mode 100644 index 0cd2562..0000000 --- a/libgo/go/exp/sql/driver/driver.go +++ /dev/null @@ -1,207 +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 driver defines interfaces to be implemented by database -// drivers as used by package sql. -// -// Code simply using databases should use package sql. -// -// Drivers only need to be aware of a subset of Go's types. The sql package -// will convert all types into one of the following: -// -// int64 -// float64 -// bool -// nil -// []byte -// string [*] everywhere except from Rows.Next. -// time.Time -// -package driver - -import "errors" - -// Driver is the interface that must be implemented by a database -// driver. -type Driver interface { - // Open returns a new connection to the database. - // The name is a string in a driver-specific format. - // - // Open may return a cached connection (one previously - // closed), but doing so is unnecessary; the sql package - // maintains a pool of idle connections for efficient re-use. - // - // The returned connection is only used by one goroutine at a - // time. - Open(name string) (Conn, error) -} - -// ErrSkip may be returned by some optional interfaces' methods to -// indicate at runtime that the fast path is unavailable and the sql -// package should continue as if the optional interface was not -// implemented. ErrSkip is only supported where explicitly -// documented. -var ErrSkip = errors.New("driver: skip fast-path; continue as if unimplemented") - -// Execer is an optional interface that may be implemented by a Conn. -// -// If a Conn does not implement Execer, the db package's DB.Exec will -// first prepare a query, execute the statement, and then close the -// statement. -// -// All arguments are of a subset type as defined in the package docs. -// -// Exec may return ErrSkip. -type Execer interface { - Exec(query string, args []interface{}) (Result, error) -} - -// Conn is a connection to a database. It is not used concurrently -// by multiple goroutines. -// -// Conn is assumed to be stateful. -type Conn interface { - // Prepare returns a prepared statement, bound to this connection. - Prepare(query string) (Stmt, error) - - // Close invalidates and potentially stops any current - // prepared statements and transactions, marking this - // connection as no longer in use. - // - // Because the sql package maintains a free pool of - // connections and only calls Close when there's a surplus of - // idle connections, it shouldn't be necessary for drivers to - // do their own connection caching. - Close() error - - // Begin starts and returns a new transaction. - Begin() (Tx, error) -} - -// Result is the result of a query execution. -type Result interface { - // LastInsertId returns the database's auto-generated ID - // after, for example, an INSERT into a table with primary - // key. - LastInsertId() (int64, error) - - // RowsAffected returns the number of rows affected by the - // query. - RowsAffected() (int64, error) -} - -// Stmt is a prepared statement. It is bound to a Conn and not -// used by multiple goroutines concurrently. -type Stmt interface { - // Close closes the statement. - // - // Closing a statement should not interrupt any outstanding - // query created from that statement. That is, the following - // order of operations is valid: - // - // * create a driver statement - // * call Query on statement, returning Rows - // * close the statement - // * read from Rows - // - // If closing a statement invalidates currently-running - // queries, the final step above will incorrectly fail. - // - // TODO(bradfitz): possibly remove the restriction above, if - // enough driver authors object and find it complicates their - // code too much. The sql package could be smarter about - // refcounting the statement and closing it at the appropriate - // time. - Close() error - - // NumInput returns the number of placeholder parameters. - // - // If NumInput returns >= 0, the sql package will sanity check - // argument counts from callers and return errors to the caller - // before the statement's Exec or Query methods are called. - // - // NumInput may also return -1, if the driver doesn't know - // its number of placeholders. In that case, the sql package - // will not sanity check Exec or Query argument counts. - NumInput() int - - // Exec executes a query that doesn't return rows, such - // as an INSERT or UPDATE. The args are all of a subset - // type as defined above. - Exec(args []interface{}) (Result, error) - - // Exec executes a query that may return rows, such as a - // SELECT. The args of all of a subset type as defined above. - Query(args []interface{}) (Rows, error) -} - -// ColumnConverter may be optionally implemented by Stmt if the -// the statement is aware of its own columns' types and can -// convert from any type to a driver subset type. -type ColumnConverter interface { - // ColumnConverter returns a ValueConverter for the provided - // column index. If the type of a specific column isn't known - // or shouldn't be handled specially, DefaultValueConverter - // can be returned. - ColumnConverter(idx int) ValueConverter -} - -// Rows is an iterator over an executed query's results. -type Rows interface { - // Columns returns the names of the columns. The number of - // columns of the result is inferred from the length of the - // slice. If a particular column name isn't known, an empty - // string should be returned for that entry. - Columns() []string - - // Close closes the rows iterator. - Close() error - - // Next is called to populate the next row of data into - // the provided slice. The provided slice will be the same - // size as the Columns() are wide. - // - // The dest slice may be populated with only with values - // of subset types defined above, but excluding string. - // All string values must be converted to []byte. - // - // Next should return io.EOF when there are no more rows. - Next(dest []interface{}) error -} - -// Tx is a transaction. -type Tx interface { - Commit() error - Rollback() error -} - -// RowsAffected implements Result for an INSERT or UPDATE operation -// which mutates a number of rows. -type RowsAffected int64 - -var _ Result = RowsAffected(0) - -func (RowsAffected) LastInsertId() (int64, error) { - return 0, errors.New("no LastInsertId available") -} - -func (v RowsAffected) RowsAffected() (int64, error) { - return int64(v), nil -} - -// DDLSuccess is a pre-defined Result for drivers to return when a DDL -// command succeeds. -var DDLSuccess ddlSuccess - -type ddlSuccess struct{} - -var _ Result = ddlSuccess{} - -func (ddlSuccess) LastInsertId() (int64, error) { - return 0, errors.New("no LastInsertId available after DDL statement") -} - -func (ddlSuccess) RowsAffected() (int64, error) { - return 0, errors.New("no RowsAffected available after DDL statement") -} diff --git a/libgo/go/exp/sql/driver/types.go b/libgo/go/exp/sql/driver/types.go deleted file mode 100644 index d6ba641..0000000 --- a/libgo/go/exp/sql/driver/types.go +++ /dev/null @@ -1,219 +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 driver - -import ( - "fmt" - "reflect" - "strconv" - "time" -) - -// ValueConverter is the interface providing the ConvertValue method. -// -// Various implementations of ValueConverter are provided by the -// driver package to provide consistent implementations of conversions -// between drivers. The ValueConverters have several uses: -// -// * converting from the subset types as provided by the sql package -// into a database table's specific column type and making sure it -// fits, such as making sure a particular int64 fits in a -// table's uint16 column. -// -// * converting a value as given from the database into one of the -// subset types. -// -// * by the sql package, for converting from a driver's subset type -// to a user's type in a scan. -type ValueConverter interface { - // ConvertValue converts a value to a restricted subset type. - ConvertValue(v interface{}) (interface{}, error) -} - -// Bool is a ValueConverter that converts input values to bools. -// -// The conversion rules are: -// - booleans are returned unchanged -// - for integer types, -// 1 is true -// 0 is false, -// other integers are an error -// - for strings and []byte, same rules as strconv.ParseBool -// - all other types are an error -var Bool boolType - -type boolType struct{} - -var _ ValueConverter = boolType{} - -func (boolType) String() string { return "Bool" } - -func (boolType) ConvertValue(src interface{}) (interface{}, error) { - switch s := src.(type) { - case bool: - return s, nil - case string: - b, err := strconv.ParseBool(s) - if err != nil { - return nil, fmt.Errorf("sql/driver: couldn't convert %q into type bool", s) - } - return b, nil - case []byte: - b, err := strconv.ParseBool(string(s)) - if err != nil { - return nil, fmt.Errorf("sql/driver: couldn't convert %q into type bool", s) - } - return b, nil - } - - sv := reflect.ValueOf(src) - switch sv.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - iv := sv.Int() - if iv == 1 || iv == 0 { - return iv == 1, nil - } - return nil, fmt.Errorf("sql/driver: couldn't convert %d into type bool", iv) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - uv := sv.Uint() - if uv == 1 || uv == 0 { - return uv == 1, nil - } - return nil, fmt.Errorf("sql/driver: couldn't convert %d into type bool", uv) - } - - return nil, fmt.Errorf("sql/driver: couldn't convert %v (%T) into type bool", src, src) -} - -// Int32 is a ValueConverter that converts input values to int64, -// respecting the limits of an int32 value. -var Int32 int32Type - -type int32Type struct{} - -var _ ValueConverter = int32Type{} - -func (int32Type) ConvertValue(v interface{}) (interface{}, error) { - rv := reflect.ValueOf(v) - switch rv.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - i64 := rv.Int() - if i64 > (1<<31)-1 || i64 < -(1<<31) { - return nil, fmt.Errorf("sql/driver: value %d overflows int32", v) - } - return i64, nil - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - u64 := rv.Uint() - if u64 > (1<<31)-1 { - return nil, fmt.Errorf("sql/driver: value %d overflows int32", v) - } - return int64(u64), nil - case reflect.String: - i, err := strconv.Atoi(rv.String()) - if err != nil { - return nil, fmt.Errorf("sql/driver: value %q can't be converted to int32", v) - } - return int64(i), nil - } - return nil, fmt.Errorf("sql/driver: unsupported value %v (type %T) converting to int32", v, v) -} - -// String is a ValueConverter that converts its input to a string. -// If the value is already a string or []byte, it's unchanged. -// If the value is of another type, conversion to string is done -// with fmt.Sprintf("%v", v). -var String stringType - -type stringType struct{} - -func (stringType) ConvertValue(v interface{}) (interface{}, error) { - switch v.(type) { - case string, []byte: - return v, nil - } - return fmt.Sprintf("%v", v), nil -} - -// IsParameterSubsetType reports whether v is of a valid type for a -// parameter. These types are: -// -// int64 -// float64 -// bool -// nil -// []byte -// time.Time -// string -// -// This is the same list as IsScanSubsetType, with the addition of -// string. -func IsParameterSubsetType(v interface{}) bool { - if IsScanSubsetType(v) { - return true - } - if _, ok := v.(string); ok { - return true - } - return false -} - -// IsScanSubsetType reports whether v is of a valid type for a -// value populated by Rows.Next. These types are: -// -// int64 -// float64 -// bool -// nil -// []byte -// time.Time -// -// This is the same list as IsParameterSubsetType, without string. -func IsScanSubsetType(v interface{}) bool { - if v == nil { - return true - } - switch v.(type) { - case int64, float64, []byte, bool, time.Time: - return true - } - return false -} - -// DefaultParameterConverter is the default implementation of -// ValueConverter that's used when a Stmt doesn't implement -// ColumnConverter. -// -// DefaultParameterConverter returns the given value directly if -// IsSubsetType(value). Otherwise integer type are converted to -// int64, floats to float64, and strings to []byte. Other types are -// an error. -var DefaultParameterConverter defaultConverter - -type defaultConverter struct{} - -var _ ValueConverter = defaultConverter{} - -func (defaultConverter) ConvertValue(v interface{}) (interface{}, error) { - if IsParameterSubsetType(v) { - return v, nil - } - - rv := reflect.ValueOf(v) - switch rv.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return rv.Int(), nil - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32: - return int64(rv.Uint()), nil - case reflect.Uint64: - u64 := rv.Uint() - if u64 >= 1<<63 { - return nil, fmt.Errorf("uint64 values with high bit set are not supported") - } - return int64(u64), nil - case reflect.Float32, reflect.Float64: - return rv.Float(), nil - } - return nil, fmt.Errorf("unsupported type %s", rv.Kind()) -} diff --git a/libgo/go/exp/sql/driver/types_test.go b/libgo/go/exp/sql/driver/types_test.go deleted file mode 100644 index 966bc6b..0000000 --- a/libgo/go/exp/sql/driver/types_test.go +++ /dev/null @@ -1,61 +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 driver - -import ( - "reflect" - "testing" - "time" -) - -type valueConverterTest struct { - c ValueConverter - in interface{} - out interface{} - err string -} - -var now = time.Now() - -var valueConverterTests = []valueConverterTest{ - {Bool, "true", true, ""}, - {Bool, "True", true, ""}, - {Bool, []byte("t"), true, ""}, - {Bool, true, true, ""}, - {Bool, "1", true, ""}, - {Bool, 1, true, ""}, - {Bool, int64(1), true, ""}, - {Bool, uint16(1), true, ""}, - {Bool, "false", false, ""}, - {Bool, false, false, ""}, - {Bool, "0", false, ""}, - {Bool, 0, false, ""}, - {Bool, int64(0), false, ""}, - {Bool, uint16(0), false, ""}, - {c: Bool, in: "foo", err: "sql/driver: couldn't convert \"foo\" into type bool"}, - {c: Bool, in: 2, err: "sql/driver: couldn't convert 2 into type bool"}, - {DefaultParameterConverter, now, now, ""}, -} - -func TestValueConverters(t *testing.T) { - for i, tt := range valueConverterTests { - out, err := tt.c.ConvertValue(tt.in) - goterr := "" - if err != nil { - goterr = err.Error() - } - if goterr != tt.err { - t.Errorf("test %d: %s(%T(%v)) error = %q; want error = %q", - i, tt.c, tt.in, tt.in, goterr, tt.err) - } - if tt.err != "" { - continue - } - if !reflect.DeepEqual(out, tt.out) { - t.Errorf("test %d: %s(%T(%v)) = %v (%T); want %v (%T)", - i, tt.c, tt.in, tt.in, out, out, tt.out, tt.out) - } - } -} diff --git a/libgo/go/exp/sql/fakedb_test.go b/libgo/go/exp/sql/fakedb_test.go deleted file mode 100644 index 70aa68c..0000000 --- a/libgo/go/exp/sql/fakedb_test.go +++ /dev/null @@ -1,597 +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 sql - -import ( - "errors" - "fmt" - "io" - "log" - "strconv" - "strings" - "sync" - "time" - - "exp/sql/driver" -) - -var _ = log.Printf - -// fakeDriver is a fake database that implements Go's driver.Driver -// interface, just for testing. -// -// It speaks a query language that's semantically similar to but -// syntantically different and simpler than SQL. The syntax is as -// follows: -// -// WIPE -// CREATE||=,=,... -// where types are: "string", [u]int{8,16,32,64}, "bool" -// INSERT||col=val,col2=val2,col3=? -// SELECT||projectcol1,projectcol2|filtercol=?,filtercol2=? -// -// When opening a a fakeDriver's database, it starts empty with no -// tables. All tables and data are stored in memory only. -type fakeDriver struct { - mu sync.Mutex - openCount int - dbs map[string]*fakeDB -} - -type fakeDB struct { - name string - - mu sync.Mutex - free []*fakeConn - tables map[string]*table -} - -type table struct { - mu sync.Mutex - colname []string - coltype []string - rows []*row -} - -func (t *table) columnIndex(name string) int { - for n, nname := range t.colname { - if name == nname { - return n - } - } - return -1 -} - -type row struct { - cols []interface{} // must be same size as its table colname + coltype -} - -func (r *row) clone() *row { - nrow := &row{cols: make([]interface{}, len(r.cols))} - copy(nrow.cols, r.cols) - return nrow -} - -type fakeConn struct { - db *fakeDB // where to return ourselves to - - currTx *fakeTx - - // Stats for tests: - mu sync.Mutex - stmtsMade int - stmtsClosed int -} - -func (c *fakeConn) incrStat(v *int) { - c.mu.Lock() - *v++ - c.mu.Unlock() -} - -type fakeTx struct { - c *fakeConn -} - -type fakeStmt struct { - c *fakeConn - q string // just for debugging - - cmd string - table string - - closed bool - - colName []string // used by CREATE, INSERT, SELECT (selected columns) - colType []string // used by CREATE - colValue []interface{} // used by INSERT (mix of strings and "?" for bound params) - placeholders int // used by INSERT/SELECT: number of ? params - - whereCol []string // used by SELECT (all placeholders) - - placeholderConverter []driver.ValueConverter // used by INSERT -} - -var fdriver driver.Driver = &fakeDriver{} - -func init() { - Register("test", fdriver) -} - -// Supports dsn forms: -// -// ; (no currently supported options) -func (d *fakeDriver) Open(dsn string) (driver.Conn, error) { - parts := strings.Split(dsn, ";") - if len(parts) < 1 { - return nil, errors.New("fakedb: no database name") - } - name := parts[0] - - db := d.getDB(name) - - d.mu.Lock() - d.openCount++ - d.mu.Unlock() - return &fakeConn{db: db}, nil -} - -func (d *fakeDriver) getDB(name string) *fakeDB { - d.mu.Lock() - defer d.mu.Unlock() - if d.dbs == nil { - d.dbs = make(map[string]*fakeDB) - } - db, ok := d.dbs[name] - if !ok { - db = &fakeDB{name: name} - d.dbs[name] = db - } - return db -} - -func (db *fakeDB) wipe() { - db.mu.Lock() - defer db.mu.Unlock() - db.tables = nil -} - -func (db *fakeDB) createTable(name string, columnNames, columnTypes []string) error { - db.mu.Lock() - defer db.mu.Unlock() - if db.tables == nil { - db.tables = make(map[string]*table) - } - if _, exist := db.tables[name]; exist { - return fmt.Errorf("table %q already exists", name) - } - if len(columnNames) != len(columnTypes) { - return fmt.Errorf("create table of %q len(names) != len(types): %d vs %d", - name, len(columnNames), len(columnTypes)) - } - db.tables[name] = &table{colname: columnNames, coltype: columnTypes} - return nil -} - -// must be called with db.mu lock held -func (db *fakeDB) table(table string) (*table, bool) { - if db.tables == nil { - return nil, false - } - t, ok := db.tables[table] - return t, ok -} - -func (db *fakeDB) columnType(table, column string) (typ string, ok bool) { - db.mu.Lock() - defer db.mu.Unlock() - t, ok := db.table(table) - if !ok { - return - } - for n, cname := range t.colname { - if cname == column { - return t.coltype[n], true - } - } - return "", false -} - -func (c *fakeConn) Begin() (driver.Tx, error) { - if c.currTx != nil { - return nil, errors.New("already in a transaction") - } - c.currTx = &fakeTx{c: c} - return c.currTx, nil -} - -func (c *fakeConn) Close() error { - if c.currTx != nil { - return errors.New("can't close; in a Transaction") - } - if c.db == nil { - return errors.New("can't close; already closed") - } - c.db = nil - return nil -} - -func checkSubsetTypes(args []interface{}) error { - for n, arg := range args { - switch arg.(type) { - case int64, float64, bool, nil, []byte, string, time.Time: - default: - return fmt.Errorf("fakedb_test: invalid argument #%d: %v, type %T", n+1, arg, arg) - } - } - return nil -} - -func (c *fakeConn) Exec(query string, args []interface{}) (driver.Result, error) { - // This is an optional interface, but it's implemented here - // just to check that all the args of of the proper types. - // ErrSkip is returned so the caller acts as if we didn't - // implement this at all. - err := checkSubsetTypes(args) - if err != nil { - return nil, err - } - return nil, driver.ErrSkip -} - -func errf(msg string, args ...interface{}) error { - return errors.New("fakedb: " + fmt.Sprintf(msg, args...)) -} - -// parts are table|selectCol1,selectCol2|whereCol=?,whereCol2=? -// (note that where where columns must always contain ? marks, -// just a limitation for fakedb) -func (c *fakeConn) prepareSelect(stmt *fakeStmt, parts []string) (driver.Stmt, error) { - if len(parts) != 3 { - return nil, errf("invalid SELECT syntax with %d parts; want 3", len(parts)) - } - stmt.table = parts[0] - stmt.colName = strings.Split(parts[1], ",") - for n, colspec := range strings.Split(parts[2], ",") { - if colspec == "" { - continue - } - nameVal := strings.Split(colspec, "=") - if len(nameVal) != 2 { - return nil, errf("SELECT on table %q has invalid column spec of %q (index %d)", stmt.table, colspec, n) - } - column, value := nameVal[0], nameVal[1] - _, ok := c.db.columnType(stmt.table, column) - if !ok { - return nil, errf("SELECT on table %q references non-existent column %q", stmt.table, column) - } - if value != "?" { - return nil, errf("SELECT on table %q has pre-bound value for where column %q; need a question mark", - stmt.table, column) - } - stmt.whereCol = append(stmt.whereCol, column) - stmt.placeholders++ - } - return stmt, nil -} - -// parts are table|col=type,col2=type2 -func (c *fakeConn) prepareCreate(stmt *fakeStmt, parts []string) (driver.Stmt, error) { - if len(parts) != 2 { - return nil, errf("invalid CREATE syntax with %d parts; want 2", len(parts)) - } - stmt.table = parts[0] - for n, colspec := range strings.Split(parts[1], ",") { - nameType := strings.Split(colspec, "=") - if len(nameType) != 2 { - return nil, errf("CREATE table %q has invalid column spec of %q (index %d)", stmt.table, colspec, n) - } - stmt.colName = append(stmt.colName, nameType[0]) - stmt.colType = append(stmt.colType, nameType[1]) - } - return stmt, nil -} - -// parts are table|col=?,col2=val -func (c *fakeConn) prepareInsert(stmt *fakeStmt, parts []string) (driver.Stmt, error) { - if len(parts) != 2 { - return nil, errf("invalid INSERT syntax with %d parts; want 2", len(parts)) - } - stmt.table = parts[0] - for n, colspec := range strings.Split(parts[1], ",") { - nameVal := strings.Split(colspec, "=") - if len(nameVal) != 2 { - return nil, errf("INSERT table %q has invalid column spec of %q (index %d)", stmt.table, colspec, n) - } - column, value := nameVal[0], nameVal[1] - ctype, ok := c.db.columnType(stmt.table, column) - if !ok { - return nil, errf("INSERT table %q references non-existent column %q", stmt.table, column) - } - stmt.colName = append(stmt.colName, column) - - if value != "?" { - var subsetVal interface{} - // Convert to driver subset type - switch ctype { - case "string": - subsetVal = []byte(value) - case "blob": - subsetVal = []byte(value) - case "int32": - i, err := strconv.Atoi(value) - if err != nil { - return nil, errf("invalid conversion to int32 from %q", value) - } - subsetVal = int64(i) // int64 is a subset type, but not int32 - default: - return nil, errf("unsupported conversion for pre-bound parameter %q to type %q", value, ctype) - } - stmt.colValue = append(stmt.colValue, subsetVal) - } else { - stmt.placeholders++ - stmt.placeholderConverter = append(stmt.placeholderConverter, converterForType(ctype)) - stmt.colValue = append(stmt.colValue, "?") - } - } - return stmt, nil -} - -func (c *fakeConn) Prepare(query string) (driver.Stmt, error) { - if c.db == nil { - panic("nil c.db; conn = " + fmt.Sprintf("%#v", c)) - } - parts := strings.Split(query, "|") - if len(parts) < 1 { - return nil, errf("empty query") - } - cmd := parts[0] - parts = parts[1:] - stmt := &fakeStmt{q: query, c: c, cmd: cmd} - c.incrStat(&c.stmtsMade) - switch cmd { - case "WIPE": - // Nothing - case "SELECT": - return c.prepareSelect(stmt, parts) - case "CREATE": - return c.prepareCreate(stmt, parts) - case "INSERT": - return c.prepareInsert(stmt, parts) - default: - return nil, errf("unsupported command type %q", cmd) - } - return stmt, nil -} - -func (s *fakeStmt) ColumnConverter(idx int) driver.ValueConverter { - return s.placeholderConverter[idx] -} - -func (s *fakeStmt) Close() error { - if !s.closed { - s.c.incrStat(&s.c.stmtsClosed) - s.closed = true - } - return nil -} - -var errClosed = errors.New("fakedb: statement has been closed") - -func (s *fakeStmt) Exec(args []interface{}) (driver.Result, error) { - if s.closed { - return nil, errClosed - } - err := checkSubsetTypes(args) - if err != nil { - return nil, err - } - - db := s.c.db - switch s.cmd { - case "WIPE": - db.wipe() - return driver.DDLSuccess, nil - case "CREATE": - if err := db.createTable(s.table, s.colName, s.colType); err != nil { - return nil, err - } - return driver.DDLSuccess, nil - case "INSERT": - return s.execInsert(args) - } - fmt.Printf("EXEC statement, cmd=%q: %#v\n", s.cmd, s) - return nil, fmt.Errorf("unimplemented statement Exec command type of %q", s.cmd) -} - -func (s *fakeStmt) execInsert(args []interface{}) (driver.Result, error) { - db := s.c.db - if len(args) != s.placeholders { - panic("error in pkg db; should only get here if size is correct") - } - db.mu.Lock() - t, ok := db.table(s.table) - db.mu.Unlock() - if !ok { - return nil, fmt.Errorf("fakedb: table %q doesn't exist", s.table) - } - - t.mu.Lock() - defer t.mu.Unlock() - - cols := make([]interface{}, len(t.colname)) - argPos := 0 - for n, colname := range s.colName { - colidx := t.columnIndex(colname) - if colidx == -1 { - return nil, fmt.Errorf("fakedb: column %q doesn't exist or dropped since prepared statement was created", colname) - } - var val interface{} - if strvalue, ok := s.colValue[n].(string); ok && strvalue == "?" { - val = args[argPos] - argPos++ - } else { - val = s.colValue[n] - } - cols[colidx] = val - } - - t.rows = append(t.rows, &row{cols: cols}) - return driver.RowsAffected(1), nil -} - -func (s *fakeStmt) Query(args []interface{}) (driver.Rows, error) { - if s.closed { - return nil, errClosed - } - err := checkSubsetTypes(args) - if err != nil { - return nil, err - } - - db := s.c.db - if len(args) != s.placeholders { - panic("error in pkg db; should only get here if size is correct") - } - - db.mu.Lock() - t, ok := db.table(s.table) - db.mu.Unlock() - if !ok { - return nil, fmt.Errorf("fakedb: table %q doesn't exist", s.table) - } - t.mu.Lock() - defer t.mu.Unlock() - - colIdx := make(map[string]int) // select column name -> column index in table - for _, name := range s.colName { - idx := t.columnIndex(name) - if idx == -1 { - return nil, fmt.Errorf("fakedb: unknown column name %q", name) - } - colIdx[name] = idx - } - - mrows := []*row{} -rows: - for _, trow := range t.rows { - // Process the where clause, skipping non-match rows. This is lazy - // and just uses fmt.Sprintf("%v") to test equality. Good enough - // for test code. - for widx, wcol := range s.whereCol { - idx := t.columnIndex(wcol) - if idx == -1 { - return nil, fmt.Errorf("db: invalid where clause column %q", wcol) - } - tcol := trow.cols[idx] - if bs, ok := tcol.([]byte); ok { - // lazy hack to avoid sprintf %v on a []byte - tcol = string(bs) - } - if fmt.Sprintf("%v", tcol) != fmt.Sprintf("%v", args[widx]) { - continue rows - } - } - mrow := &row{cols: make([]interface{}, len(s.colName))} - for seli, name := range s.colName { - mrow.cols[seli] = trow.cols[colIdx[name]] - } - mrows = append(mrows, mrow) - } - - cursor := &rowsCursor{ - pos: -1, - rows: mrows, - cols: s.colName, - } - return cursor, nil -} - -func (s *fakeStmt) NumInput() int { - return s.placeholders -} - -func (tx *fakeTx) Commit() error { - tx.c.currTx = nil - return nil -} - -func (tx *fakeTx) Rollback() error { - tx.c.currTx = nil - return nil -} - -type rowsCursor struct { - cols []string - pos int - rows []*row - closed bool - - // a clone of slices to give out to clients, indexed by the - // the original slice's first byte address. we clone them - // just so we're able to corrupt them on close. - bytesClone map[*byte][]byte -} - -func (rc *rowsCursor) Close() error { - if !rc.closed { - for _, bs := range rc.bytesClone { - bs[0] = 255 // first byte corrupted - } - } - rc.closed = true - return nil -} - -func (rc *rowsCursor) Columns() []string { - return rc.cols -} - -func (rc *rowsCursor) Next(dest []interface{}) error { - if rc.closed { - return errors.New("fakedb: cursor is closed") - } - rc.pos++ - if rc.pos >= len(rc.rows) { - return io.EOF // per interface spec - } - for i, v := range rc.rows[rc.pos].cols { - // TODO(bradfitz): convert to subset types? naah, I - // think the subset types should only be input to - // driver, but the sql package should be able to handle - // a wider range of types coming out of drivers. all - // for ease of drivers, and to prevent drivers from - // messing up conversions or doing them differently. - dest[i] = v - - if bs, ok := v.([]byte); ok { - if rc.bytesClone == nil { - rc.bytesClone = make(map[*byte][]byte) - } - clone, ok := rc.bytesClone[&bs[0]] - if !ok { - clone = make([]byte, len(bs)) - copy(clone, bs) - rc.bytesClone[&bs[0]] = clone - } - dest[i] = clone - } - } - return nil -} - -func converterForType(typ string) driver.ValueConverter { - switch typ { - case "bool": - return driver.Bool - case "int32": - return driver.Int32 - case "string": - return driver.String - case "datetime": - return driver.DefaultParameterConverter - } - panic("invalid fakedb column type of " + typ) -} diff --git a/libgo/go/exp/sql/sql.go b/libgo/go/exp/sql/sql.go deleted file mode 100644 index 4e68c3e..0000000 --- a/libgo/go/exp/sql/sql.go +++ /dev/null @@ -1,860 +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 sql provides a generic interface around SQL (or SQL-like) -// databases. -package sql - -import ( - "errors" - "fmt" - "io" - "sync" - - "exp/sql/driver" -) - -var drivers = make(map[string]driver.Driver) - -// Register makes a database driver available by the provided name. -// If Register is called twice with the same name or if driver is nil, -// it panics. -func Register(name string, driver driver.Driver) { - if driver == nil { - panic("sql: Register driver is nil") - } - if _, dup := drivers[name]; dup { - panic("sql: Register called twice for driver " + name) - } - drivers[name] = driver -} - -// NullableString represents a string that may be null. -// NullableString implements the ScannerInto interface so -// it can be used as a scan destination: -// -// var s NullableString -// err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&s) -// ... -// if s.Valid { -// // use s.String -// } else { -// // NULL value -// } -// -// TODO(bradfitz): add other types. -type NullableString struct { - String string - Valid bool // Valid is true if String is not NULL -} - -// ScanInto implements the ScannerInto interface. -func (ms *NullableString) ScanInto(value interface{}) error { - if value == nil { - ms.String, ms.Valid = "", false - return nil - } - ms.Valid = true - return convertAssign(&ms.String, value) -} - -// ScannerInto is an interface used by Scan. -type ScannerInto interface { - // ScanInto assigns a value from a database driver. - // - // The value will be of one of the following restricted - // set of types: - // - // int64 - // float64 - // bool - // []byte - // nil - for NULL values - // - // An error should be returned if the value can not be stored - // without loss of information. - ScanInto(value interface{}) error -} - -// 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("sql: no rows in result set") - -// DB is a database handle. It's safe for concurrent use by multiple -// goroutines. -type DB struct { - driver driver.Driver - dsn string - - mu sync.Mutex // protects freeConn and closed - freeConn []driver.Conn - closed bool -} - -// Open opens a database specified by its database driver name and a -// driver-specific data source name, usually consisting of at least a -// database name and connection information. -// -// Most users will open a database via a driver-specific connection -// helper function that returns a *DB. -func Open(driverName, dataSourceName string) (*DB, error) { - driver, ok := drivers[driverName] - if !ok { - return nil, fmt.Errorf("sql: unknown driver %q (forgotten import?)", driverName) - } - return &DB{driver: driver, dsn: dataSourceName}, nil -} - -// Close closes the database, releasing any open resources. -func (db *DB) Close() error { - db.mu.Lock() - defer db.mu.Unlock() - var err error - for _, c := range db.freeConn { - err1 := c.Close() - if err1 != nil { - err = err1 - } - } - db.freeConn = nil - db.closed = true - return err -} - -func (db *DB) maxIdleConns() int { - const defaultMaxIdleConns = 2 - // TODO(bradfitz): ask driver, if supported, for its default preference - // TODO(bradfitz): let users override? - return defaultMaxIdleConns -} - -// conn returns a newly-opened or cached driver.Conn -func (db *DB) conn() (driver.Conn, error) { - db.mu.Lock() - if db.closed { - db.mu.Unlock() - return nil, errors.New("sql: database is closed") - } - if n := len(db.freeConn); n > 0 { - conn := db.freeConn[n-1] - db.freeConn = db.freeConn[:n-1] - db.mu.Unlock() - return conn, nil - } - db.mu.Unlock() - return db.driver.Open(db.dsn) -} - -func (db *DB) connIfFree(wanted driver.Conn) (conn driver.Conn, ok bool) { - db.mu.Lock() - defer db.mu.Unlock() - for n, conn := range db.freeConn { - if conn == wanted { - db.freeConn[n] = db.freeConn[len(db.freeConn)-1] - db.freeConn = db.freeConn[:len(db.freeConn)-1] - return wanted, true - } - } - return nil, false -} - -func (db *DB) putConn(c driver.Conn) { - db.mu.Lock() - defer db.mu.Unlock() - if n := len(db.freeConn); !db.closed && n < db.maxIdleConns() { - db.freeConn = append(db.freeConn, c) - return - } - db.closeConn(c) // TODO(bradfitz): release lock before calling this? -} - -func (db *DB) closeConn(c driver.Conn) { - // TODO: check to see if we need this Conn for any prepared statements - // that are active. - c.Close() -} - -// Prepare creates a prepared statement for later execution. -func (db *DB) Prepare(query string) (*Stmt, error) { - // TODO: check if db.driver supports an optional - // driver.Preparer interface and call that instead, if so, - // otherwise we make a prepared statement that's bound - // to a connection, and to execute this prepared statement - // we either need to use this connection (if it's free), else - // get a new connection + re-prepare + execute on that one. - ci, err := db.conn() - if err != nil { - return nil, err - } - defer db.putConn(ci) - si, err := ci.Prepare(query) - if err != nil { - return nil, err - } - stmt := &Stmt{ - db: db, - query: query, - css: []connStmt{{ci, si}}, - } - return stmt, nil -} - -// Exec executes a query without returning any rows. -func (db *DB) Exec(query string, args ...interface{}) (Result, error) { - sargs, err := subsetTypeArgs(args) - if err != nil { - return nil, err - } - - ci, err := db.conn() - if err != nil { - return nil, err - } - defer db.putConn(ci) - - if execer, ok := ci.(driver.Execer); ok { - resi, err := execer.Exec(query, sargs) - if err != driver.ErrSkip { - if err != nil { - return nil, err - } - return result{resi}, nil - } - } - - sti, err := ci.Prepare(query) - if err != nil { - return nil, err - } - defer sti.Close() - - resi, err := sti.Exec(sargs) - if err != nil { - return nil, err - } - return result{resi}, nil -} - -// Query executes a query that returns rows, typically a SELECT. -func (db *DB) Query(query string, args ...interface{}) (*Rows, error) { - stmt, err := db.Prepare(query) - if err != nil { - return nil, err - } - rows, err := stmt.Query(args...) - if err != nil { - stmt.Close() - return nil, err - } - rows.closeStmt = stmt - return rows, nil -} - -// QueryRow executes a query that is expected to return at most one row. -// QueryRow always return a non-nil value. Errors are deferred until -// Row's Scan method is called. -func (db *DB) QueryRow(query string, args ...interface{}) *Row { - rows, err := db.Query(query, args...) - return &Row{rows: rows, err: err} -} - -// Begin starts a transaction. The isolation level is dependent on -// the driver. -func (db *DB) Begin() (*Tx, error) { - ci, err := db.conn() - if err != nil { - return nil, err - } - txi, err := ci.Begin() - if err != nil { - db.putConn(ci) - return nil, fmt.Errorf("sql: failed to Begin transaction: %v", err) - } - return &Tx{ - db: db, - ci: ci, - txi: txi, - }, nil -} - -// DriverDatabase returns the database's underlying driver. -func (db *DB) Driver() driver.Driver { - return db.driver -} - -// Tx is an in-progress database transaction. -// -// A transaction must end with a call to Commit or Rollback. -// -// After a call to Commit or Rollback, all operations on the -// transaction fail with ErrTransactionFinished. -type Tx struct { - db *DB - - // ci is owned exclusively until Commit or Rollback, at which point - // it's returned with putConn. - ci driver.Conn - txi driver.Tx - - // cimu is held while somebody is using ci (between grabConn - // and releaseConn) - cimu sync.Mutex - - // done transitions from false to true exactly once, on Commit - // or Rollback. once done, all operations fail with - // ErrTransactionFinished. - done bool -} - -var ErrTransactionFinished = errors.New("sql: Transaction has already been committed or rolled back") - -func (tx *Tx) close() { - if tx.done { - panic("double close") // internal error - } - tx.done = true - tx.db.putConn(tx.ci) - tx.ci = nil - tx.txi = nil -} - -func (tx *Tx) grabConn() (driver.Conn, error) { - if tx.done { - return nil, ErrTransactionFinished - } - tx.cimu.Lock() - return tx.ci, nil -} - -func (tx *Tx) releaseConn() { - tx.cimu.Unlock() -} - -// Commit commits the transaction. -func (tx *Tx) Commit() error { - if tx.done { - return ErrTransactionFinished - } - defer tx.close() - return tx.txi.Commit() -} - -// Rollback aborts the transaction. -func (tx *Tx) Rollback() error { - if tx.done { - return ErrTransactionFinished - } - defer tx.close() - return tx.txi.Rollback() -} - -// Prepare creates a prepared statement for use within a transaction. -// -// The returned statement operates within the transaction and can no longer -// be used once the transaction has been committed or rolled back. -// -// To use an existing prepared statement on this transaction, see Tx.Stmt. -func (tx *Tx) Prepare(query string) (*Stmt, error) { - // TODO(bradfitz): We could be more efficient here and either - // provide a method to take an existing Stmt (created on - // perhaps a different Conn), and re-create it on this Conn if - // necessary. Or, better: keep a map in DB of query string to - // Stmts, and have Stmt.Execute do the right thing and - // re-prepare if the Conn in use doesn't have that prepared - // statement. But we'll want to avoid caching the statement - // in the case where we only call conn.Prepare implicitly - // (such as in db.Exec or tx.Exec), but the caller package - // can't be holding a reference to the returned statement. - // Perhaps just looking at the reference count (by noting - // Stmt.Close) would be enough. We might also want a finalizer - // on Stmt to drop the reference count. - ci, err := tx.grabConn() - if err != nil { - return nil, err - } - defer tx.releaseConn() - - si, err := ci.Prepare(query) - if err != nil { - return nil, err - } - - stmt := &Stmt{ - db: tx.db, - tx: tx, - txsi: si, - query: query, - } - return stmt, nil -} - -// Stmt returns a transaction-specific prepared statement from -// an existing statement. -// -// Example: -// updateMoney, err := db.Prepare("UPDATE balance SET money=money+? WHERE id=?") -// ... -// tx, err := db.Begin() -// ... -// res, err := tx.Stmt(updateMoney).Exec(123.45, 98293203) -func (tx *Tx) Stmt(stmt *Stmt) *Stmt { - // TODO(bradfitz): optimize this. Currently this re-prepares - // each time. This is fine for now to illustrate the API but - // we should really cache already-prepared statements - // per-Conn. See also the big comment in Tx.Prepare. - - if tx.db != stmt.db { - return &Stmt{stickyErr: errors.New("sql: Tx.Stmt: statement from different database used")} - } - ci, err := tx.grabConn() - if err != nil { - return &Stmt{stickyErr: err} - } - defer tx.releaseConn() - si, err := ci.Prepare(stmt.query) - return &Stmt{ - db: tx.db, - tx: tx, - txsi: si, - query: stmt.query, - stickyErr: err, - } -} - -// Exec executes a query that doesn't return rows. -// For example: an INSERT and UPDATE. -func (tx *Tx) Exec(query string, args ...interface{}) (Result, error) { - ci, err := tx.grabConn() - if err != nil { - return nil, err - } - defer tx.releaseConn() - - if execer, ok := ci.(driver.Execer); ok { - resi, err := execer.Exec(query, args) - if err != nil { - return nil, err - } - return result{resi}, nil - } - - sti, err := ci.Prepare(query) - if err != nil { - return nil, err - } - defer sti.Close() - - sargs, err := subsetTypeArgs(args) - if err != nil { - return nil, err - } - - resi, err := sti.Exec(sargs) - if err != nil { - return nil, err - } - return result{resi}, nil -} - -// Query executes a query that returns rows, typically a SELECT. -func (tx *Tx) Query(query string, args ...interface{}) (*Rows, error) { - if tx.done { - return nil, ErrTransactionFinished - } - stmt, err := tx.Prepare(query) - if err != nil { - return nil, err - } - defer stmt.Close() - return stmt.Query(args...) -} - -// QueryRow executes a query that is expected to return at most one row. -// QueryRow always return a non-nil value. Errors are deferred until -// Row's Scan method is called. -func (tx *Tx) QueryRow(query string, args ...interface{}) *Row { - rows, err := tx.Query(query, args...) - return &Row{rows: rows, err: err} -} - -// connStmt is a prepared statement on a particular connection. -type connStmt struct { - ci driver.Conn - si driver.Stmt -} - -// Stmt is a prepared statement. Stmt is safe for concurrent use by multiple goroutines. -type Stmt struct { - // Immutable: - db *DB // where we came from - query string // that created the Stmt - stickyErr error // if non-nil, this error is returned for all operations - - // If in a transaction, else both nil: - tx *Tx - txsi driver.Stmt - - mu sync.Mutex // protects the rest of the fields - closed bool - - // css is a list of underlying driver statement interfaces - // that are valid on particular connections. This is only - // used if tx == nil and one is found that has idle - // connections. If tx != nil, txsi is always used. - css []connStmt -} - -// Exec executes a prepared statement with the given arguments and -// returns a Result summarizing the effect of the statement. -func (s *Stmt) Exec(args ...interface{}) (Result, error) { - _, releaseConn, si, err := s.connStmt() - if err != nil { - return nil, err - } - defer releaseConn() - - // -1 means the driver doesn't know how to count the number of - // placeholders, so we won't sanity check input here and instead let the - // driver deal with errors. - if want := si.NumInput(); want != -1 && len(args) != want { - return nil, fmt.Errorf("sql: expected %d arguments, got %d", want, len(args)) - } - - // Convert args to subset types. - if cc, ok := si.(driver.ColumnConverter); ok { - for n, arg := range args { - args[n], err = cc.ColumnConverter(n).ConvertValue(arg) - if err != nil { - return nil, fmt.Errorf("sql: converting Exec argument #%d's type: %v", n, err) - } - if !driver.IsParameterSubsetType(args[n]) { - return nil, fmt.Errorf("sql: driver ColumnConverter error converted %T to unsupported type %T", - arg, args[n]) - } - } - } else { - for n, arg := range args { - args[n], err = driver.DefaultParameterConverter.ConvertValue(arg) - if err != nil { - return nil, fmt.Errorf("sql: converting Exec argument #%d's type: %v", n, err) - } - } - } - - resi, err := si.Exec(args) - if err != nil { - return nil, err - } - return result{resi}, nil -} - -// connStmt returns a free driver connection on which to execute the -// statement, a function to call to release the connection, and a -// statement bound to that connection. -func (s *Stmt) connStmt() (ci driver.Conn, releaseConn func(), si driver.Stmt, err error) { - if err = s.stickyErr; err != nil { - return - } - s.mu.Lock() - if s.closed { - s.mu.Unlock() - err = errors.New("sql: statement is closed") - return - } - - // In a transaction, we always use the connection that the - // transaction was created on. - if s.tx != nil { - s.mu.Unlock() - ci, err = s.tx.grabConn() // blocks, waiting for the connection. - if err != nil { - return - } - releaseConn = func() { s.tx.releaseConn() } - return ci, releaseConn, s.txsi, nil - } - - var cs connStmt - match := false - for _, v := range s.css { - // TODO(bradfitz): lazily clean up entries in this - // list with dead conns while enumerating - if _, match = s.db.connIfFree(cs.ci); match { - cs = v - break - } - } - s.mu.Unlock() - - // Make a new conn if all are busy. - // TODO(bradfitz): or wait for one? make configurable later? - if !match { - ci, err := s.db.conn() - if err != nil { - return nil, nil, nil, err - } - si, err := ci.Prepare(s.query) - if err != nil { - return nil, nil, nil, err - } - s.mu.Lock() - cs = connStmt{ci, si} - s.css = append(s.css, cs) - s.mu.Unlock() - } - - conn := cs.ci - releaseConn = func() { s.db.putConn(conn) } - return conn, releaseConn, cs.si, nil -} - -// Query executes a prepared query statement with the given arguments -// and returns the query results as a *Rows. -func (s *Stmt) Query(args ...interface{}) (*Rows, error) { - ci, releaseConn, si, err := s.connStmt() - if err != nil { - return nil, err - } - - // -1 means the driver doesn't know how to count the number of - // placeholders, so we won't sanity check input here and instead let the - // driver deal with errors. - if want := si.NumInput(); want != -1 && len(args) != want { - return nil, fmt.Errorf("sql: statement expects %d inputs; got %d", si.NumInput(), len(args)) - } - sargs, err := subsetTypeArgs(args) - if err != nil { - return nil, err - } - rowsi, err := si.Query(sargs) - if err != nil { - s.db.putConn(ci) - return nil, err - } - // Note: ownership of ci passes to the *Rows, to be freed - // with releaseConn. - rows := &Rows{ - db: s.db, - ci: ci, - releaseConn: releaseConn, - rowsi: rowsi, - } - return rows, nil -} - -// QueryRow executes a prepared query statement with the given arguments. -// If an error occurs during the execution of the statement, that error will -// be returned by a call to Scan on the returned *Row, which is always non-nil. -// If the query selects no rows, the *Row's Scan will return ErrNoRows. -// Otherwise, the *Row's Scan scans the first selected row and discards -// the rest. -// -// Example usage: -// -// var name string -// err := nameByUseridStmt.QueryRow(id).Scan(&s) -func (s *Stmt) QueryRow(args ...interface{}) *Row { - rows, err := s.Query(args...) - if err != nil { - return &Row{err: err} - } - return &Row{rows: rows} -} - -// Close closes the statement. -func (s *Stmt) Close() error { - if s.stickyErr != nil { - return s.stickyErr - } - s.mu.Lock() - defer s.mu.Unlock() - if s.closed { - return nil - } - s.closed = true - - if s.tx != nil { - s.txsi.Close() - } else { - for _, v := range s.css { - if ci, match := s.db.connIfFree(v.ci); match { - v.si.Close() - s.db.putConn(ci) - } else { - // TODO(bradfitz): care that we can't close - // this statement because the statement's - // connection is in use? - } - } - } - return nil -} - -// Rows is the result of a query. Its cursor starts before the first row -// of the result set. Use Next to advance through the rows: -// -// rows, err := db.Query("SELECT ...") -// ... -// for rows.Next() { -// var id int -// var name string -// err = rows.Scan(&id, &name) -// ... -// } -// err = rows.Err() // get any error encountered during iteration -// ... -type Rows struct { - db *DB - ci driver.Conn // owned; must call putconn when closed to release - releaseConn func() - rowsi driver.Rows - - closed bool - lastcols []interface{} - lasterr error - closeStmt *Stmt // if non-nil, statement to Close on close -} - -// Next prepares the next result row for reading with the Scan method. -// It returns true on success, false if there is no next result row. -// Every call to Scan, even the first one, must be preceded by a call -// to Next. -func (rs *Rows) Next() bool { - if rs.closed { - return false - } - if rs.lasterr != nil { - return false - } - if rs.lastcols == nil { - rs.lastcols = make([]interface{}, len(rs.rowsi.Columns())) - } - rs.lasterr = rs.rowsi.Next(rs.lastcols) - if rs.lasterr == io.EOF { - rs.Close() - } - return rs.lasterr == nil -} - -// Err returns the error, if any, that was encountered during iteration. -func (rs *Rows) Err() error { - if rs.lasterr == io.EOF { - return nil - } - 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("sql: Rows closed") - } - if rs.lasterr != nil { - return rs.lasterr - } - if rs.lastcols == nil { - return errors.New("sql: Scan called without calling Next") - } - if len(dest) != len(rs.lastcols) { - 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("sql: Scan error on column index %d: %v", i, err) - } - } - return nil -} - -// Close closes the Rows, preventing further enumeration. If the -// end is encountered, the Rows are closed automatically. Close -// is idempotent. -func (rs *Rows) Close() error { - if rs.closed { - return nil - } - rs.closed = true - err := rs.rowsi.Close() - rs.releaseConn() - if rs.closeStmt != nil { - rs.closeStmt.Close() - } - return err -} - -// Row is the result of calling QueryRow to select a single row. -type Row struct { - // One of these two will be non-nil: - err error // deferred error for easy chaining - rows *Rows -} - -// Scan copies the columns from the matched row into the values -// pointed at by dest. If more than one row matches the query, -// Scan uses the first row and discards the rest. If no row matches -// the query, Scan returns ErrNoRows. -func (r *Row) Scan(dest ...interface{}) error { - if r.err != nil { - return r.err - } - defer r.rows.Close() - if !r.rows.Next() { - return ErrNoRows - } - err := r.rows.Scan(dest...) - if err != nil { - return err - } - - // TODO(bradfitz): for now we need to defensively clone all - // []byte that the driver returned, since we're about to close - // the Rows in our defer, when we return from this function. - // the contract with the driver.Next(...) interface is that it - // can return slices into read-only temporary memory that's - // only valid until the next Scan/Close. But the TODO is that - // for a lot of drivers, this copy will be unnecessary. We - // should provide an optional interface for drivers to - // implement to say, "don't worry, the []bytes that I return - // from Next will not be modified again." (for instance, if - // they were obtained from the network anyway) But for now we - // don't care. - for _, dp := range dest { - b, ok := dp.(*[]byte) - if !ok { - continue - } - clone := make([]byte, len(*b)) - copy(clone, *b) - *b = clone - } - return nil -} - -// A Result summarizes an executed SQL command. -type Result interface { - LastInsertId() (int64, error) - RowsAffected() (int64, error) -} - -type result struct { - driver.Result -} diff --git a/libgo/go/exp/sql/sql_test.go b/libgo/go/exp/sql/sql_test.go deleted file mode 100644 index 3f98a8c..0000000 --- a/libgo/go/exp/sql/sql_test.go +++ /dev/null @@ -1,305 +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 sql - -import ( - "reflect" - "strings" - "testing" - "time" -) - -const fakeDBName = "foo" - -var chrisBirthday = time.Unix(123456789, 0) - -func newTestDB(t *testing.T, name string) *DB { - db, err := Open("test", fakeDBName) - if err != nil { - t.Fatalf("Open: %v", err) - } - if _, err := db.Exec("WIPE"); err != nil { - t.Fatalf("exec wipe: %v", err) - } - if name == "people" { - exec(t, db, "CREATE|people|name=string,age=int32,photo=blob,dead=bool,bdate=datetime") - exec(t, db, "INSERT|people|name=Alice,age=?,photo=APHOTO", 1) - exec(t, db, "INSERT|people|name=Bob,age=?,photo=BPHOTO", 2) - exec(t, db, "INSERT|people|name=Chris,age=?,photo=CPHOTO,bdate=?", 3, chrisBirthday) - } - return db -} - -func exec(t *testing.T, db *DB, query string, args ...interface{}) { - _, err := db.Exec(query, args...) - if err != nil { - t.Fatalf("Exec of %q: %v", query, err) - } -} - -func closeDB(t *testing.T, db *DB) { - err := db.Close() - if err != nil { - t.Fatalf("error closing DB: %v", err) - } -} - -func TestQuery(t *testing.T) { - db := newTestDB(t, "people") - defer closeDB(t, db) - rows, err := db.Query("SELECT|people|age,name|") - if err != nil { - t.Fatalf("Query: %v", err) - } - type row struct { - age int - name string - } - got := []row{} - for rows.Next() { - var r row - err = rows.Scan(&r.age, &r.name) - if err != nil { - t.Fatalf("Scan: %v", err) - } - got = append(got, r) - } - err = rows.Err() - if err != nil { - t.Fatalf("Err: %v", err) - } - want := []row{ - {age: 1, name: "Alice"}, - {age: 2, name: "Bob"}, - {age: 3, name: "Chris"}, - } - if !reflect.DeepEqual(got, want) { - t.Logf(" got: %#v\nwant: %#v", got, want) - } - - // And verify that the final rows.Next() call, which hit EOF, - // also closed the rows connection. - if n := len(db.freeConn); n != 1 { - t.Errorf("free conns after query hitting EOF = %d; want 1", n) - } -} - -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) - var name string - var age int - var birthday time.Time - - err := db.QueryRow("SELECT|people|age,name|age=?", 3).Scan(&age) - if err == nil || !strings.Contains(err.Error(), "expected 2 destination arguments") { - t.Errorf("expected error from wrong number of arguments; actually got: %v", err) - } - - err = db.QueryRow("SELECT|people|bdate|age=?", 3).Scan(&birthday) - if err != nil || !birthday.Equal(chrisBirthday) { - t.Errorf("chris birthday = %v, err = %v; want %v", birthday, err, chrisBirthday) - } - - err = db.QueryRow("SELECT|people|age,name|age=?", 2).Scan(&age, &name) - if err != nil { - t.Fatalf("age QueryRow+Scan: %v", err) - } - if name != "Bob" { - t.Errorf("expected name Bob, got %q", name) - } - if age != 2 { - t.Errorf("expected age 2, got %d", age) - } - - err = db.QueryRow("SELECT|people|age,name|name=?", "Alice").Scan(&age, &name) - if err != nil { - t.Fatalf("name QueryRow+Scan: %v", err) - } - if name != "Alice" { - t.Errorf("expected name Alice, got %q", name) - } - if age != 1 { - t.Errorf("expected age 1, got %d", age) - } - - var photo []byte - err = db.QueryRow("SELECT|people|photo|name=?", "Alice").Scan(&photo) - if err != nil { - t.Fatalf("photo QueryRow+Scan: %v", err) - } - want := []byte("APHOTO") - if !reflect.DeepEqual(photo, want) { - t.Errorf("photo = %q; want %q", photo, want) - } -} - -func TestStatementErrorAfterClose(t *testing.T) { - db := newTestDB(t, "people") - defer closeDB(t, db) - stmt, err := db.Prepare("SELECT|people|age|name=?") - if err != nil { - t.Fatalf("Prepare: %v", err) - } - err = stmt.Close() - if err != nil { - t.Fatalf("Close: %v", err) - } - var name string - err = stmt.QueryRow("foo").Scan(&name) - if err == nil { - t.Errorf("expected error from QueryRow.Scan after Stmt.Close") - } -} - -func TestStatementQueryRow(t *testing.T) { - db := newTestDB(t, "people") - defer closeDB(t, db) - stmt, err := db.Prepare("SELECT|people|age|name=?") - if err != nil { - t.Fatalf("Prepare: %v", err) - } - var age int - for n, tt := range []struct { - name string - want int - }{ - {"Alice", 1}, - {"Bob", 2}, - {"Chris", 3}, - } { - if err := stmt.QueryRow(tt.name).Scan(&age); err != nil { - t.Errorf("%d: on %q, QueryRow/Scan: %v", n, tt.name, err) - } else if age != tt.want { - t.Errorf("%d: age=%d, want %d", n, age, tt.want) - } - } - -} - -// just a test of fakedb itself -func TestBogusPreboundParameters(t *testing.T) { - db := newTestDB(t, "foo") - defer closeDB(t, db) - exec(t, db, "CREATE|t1|name=string,age=int32,dead=bool") - _, err := db.Prepare("INSERT|t1|name=?,age=bogusconversion") - if err == nil { - t.Fatalf("expected error") - } - if err.Error() != `fakedb: invalid conversion to int32 from "bogusconversion"` { - t.Errorf("unexpected error: %v", err) - } -} - -func TestExec(t *testing.T) { - db := newTestDB(t, "foo") - defer closeDB(t, db) - exec(t, db, "CREATE|t1|name=string,age=int32,dead=bool") - stmt, err := db.Prepare("INSERT|t1|name=?,age=?") - if err != nil { - t.Errorf("Stmt, err = %v, %v", stmt, err) - } - - type execTest struct { - args []interface{} - wantErr string - } - execTests := []execTest{ - // Okay: - {[]interface{}{"Brad", 31}, ""}, - {[]interface{}{"Brad", int64(31)}, ""}, - {[]interface{}{"Bob", "32"}, ""}, - {[]interface{}{7, 9}, ""}, - - // Invalid conversions: - {[]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{}{}, "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...) - errStr := "" - if err != nil { - errStr = err.Error() - } - if errStr != et.wantErr { - t.Errorf("stmt.Execute #%d: for %v, got error %q, want error %q", - n, et.args, errStr, et.wantErr) - } - } -} - -func TestTxStmt(t *testing.T) { - db := newTestDB(t, "") - defer closeDB(t, db) - exec(t, db, "CREATE|t1|name=string,age=int32,dead=bool") - stmt, err := db.Prepare("INSERT|t1|name=?,age=?") - if err != nil { - t.Fatalf("Stmt, err = %v, %v", stmt, err) - } - tx, err := db.Begin() - if err != nil { - t.Fatalf("Begin = %v", err) - } - _, err = tx.Stmt(stmt).Exec("Bobby", 7) - if err != nil { - t.Fatalf("Exec = %v", err) - } - err = tx.Commit() - if err != nil { - t.Fatalf("Commit = %v", err) - } -} - -// Tests fix for issue 2542, that we release a lock when querying on -// a closed connection. -func TestIssue2542Deadlock(t *testing.T) { - db := newTestDB(t, "people") - closeDB(t, db) - for i := 0; i < 2; i++ { - _, err := db.Query("SELECT|people|age,name|") - if err == nil { - t.Fatalf("expected error") - } - } -} - -func TestQueryRowClosingStmt(t *testing.T) { - db := newTestDB(t, "people") - defer closeDB(t, db) - var name string - var age int - err := db.QueryRow("SELECT|people|age,name|age=?", 3).Scan(&age, &name) - if err != nil { - t.Fatal(err) - } - if len(db.freeConn) != 1 { - t.Fatalf("expected 1 free conn") - } - fakeConn := db.freeConn[0].(*fakeConn) - if made, closed := fakeConn.stmtsMade, fakeConn.stmtsClosed; made != closed { - t.Logf("statement close mismatch: made %d, closed %d", made, closed) - } -} diff --git a/libgo/go/exp/ssh/client.go b/libgo/go/exp/ssh/client.go index 8df8145..eb6c035 100644 --- a/libgo/go/exp/ssh/client.go +++ b/libgo/go/exp/ssh/client.go @@ -306,9 +306,8 @@ type clientChan struct { stdout *chanReader // receives the payload of channelData messages stderr *chanReader // receives the payload of channelExtendedData messages msg chan interface{} // incoming messages - - theyClosed bool // indicates the close msg has been received from the remote side - weClosed bool // incidates the close msg has been sent from our side + theyClosed bool // indicates the close msg has been received from the remote side + weClosed bool // incidates the close msg has been sent from our side } // newClientChan returns a partially constructed *clientChan diff --git a/libgo/go/exp/ssh/messages.go b/libgo/go/exp/ssh/messages.go index cebb560..34ad131 100644 --- a/libgo/go/exp/ssh/messages.go +++ b/libgo/go/exp/ssh/messages.go @@ -484,6 +484,26 @@ func intLength(n *big.Int) int { return length } +func marshalUint32(to []byte, n uint32) []byte { + to[0] = byte(n >> 24) + to[1] = byte(n >> 16) + to[2] = byte(n >> 8) + to[3] = byte(n) + return to[4:] +} + +func marshalUint64(to []byte, n uint64) []byte { + to[0] = byte(n >> 56) + to[1] = byte(n >> 48) + to[2] = byte(n >> 40) + to[3] = byte(n >> 32) + to[4] = byte(n >> 24) + to[5] = byte(n >> 16) + to[6] = byte(n >> 8) + to[7] = byte(n) + return to[8:] +} + func marshalInt(to []byte, n *big.Int) []byte { lengthBytes := to to = to[4:] diff --git a/libgo/go/exp/ssh/session.go b/libgo/go/exp/ssh/session.go index 807dd87..ea4addb 100644 --- a/libgo/go/exp/ssh/session.go +++ b/libgo/go/exp/ssh/session.go @@ -70,7 +70,7 @@ type Session struct { started bool // true once Start, Run or Shell is invoked. copyFuncs []func() error - errch chan error // one send per copyFunc + errors chan error // one send per copyFunc // true if pipe method is active stdinpipe, stdoutpipe, stderrpipe bool @@ -244,10 +244,10 @@ func (s *Session) start() error { setupFd(s) } - s.errch = make(chan error, len(s.copyFuncs)) + s.errors = make(chan error, len(s.copyFuncs)) for _, fn := range s.copyFuncs { go func(fn func() error) { - s.errch <- fn() + s.errors <- fn() }(fn) } return nil @@ -270,7 +270,7 @@ func (s *Session) Wait() error { var copyError error for _ = range s.copyFuncs { - if err := <-s.errch; err != nil && copyError == nil { + if err := <-s.errors; err != nil && copyError == nil { copyError = err } } diff --git a/libgo/go/exp/ssh/tcpip.go b/libgo/go/exp/ssh/tcpip.go index bee41ee..e0c47bc 100644 --- a/libgo/go/exp/ssh/tcpip.go +++ b/libgo/go/exp/ssh/tcpip.go @@ -9,6 +9,7 @@ import ( "fmt" "io" "net" + "time" ) // Dial initiates a connection to the addr from the remote host. @@ -107,27 +108,25 @@ func (t *tcpchanconn) RemoteAddr() net.Addr { return t.raddr } -// SetTimeout sets the read and write deadlines associated +// SetDeadline sets the read and write deadlines associated // with the connection. -func (t *tcpchanconn) SetTimeout(nsec int64) error { - if err := t.SetReadTimeout(nsec); err != nil { +func (t *tcpchanconn) SetDeadline(deadline time.Time) error { + if err := t.SetReadDeadline(deadline); err != nil { return err } - return t.SetWriteTimeout(nsec) + return t.SetWriteDeadline(deadline) } -// SetReadTimeout sets the time (in nanoseconds) that -// Read will wait for data before returning an error with Timeout() == true. -// Setting nsec == 0 (the default) disables the deadline. -func (t *tcpchanconn) SetReadTimeout(nsec int64) error { - return errors.New("ssh: tcpchan: timeout not supported") +// SetReadDeadline sets the read deadline. +// A zero value for t means Read will not time out. +// After the deadline, the error from Read will implement net.Error +// with Timeout() == true. +func (t *tcpchanconn) SetReadDeadline(deadline time.Time) error { + return errors.New("ssh: tcpchan: deadline not supported") } -// SetWriteTimeout sets the time (in nanoseconds) that -// Write will wait to send its data before returning an error with Timeout() == true. -// Setting nsec == 0 (the default) disables the deadline. -// Even if write times out, it may return n > 0, indicating that -// some of the data was successfully written. -func (t *tcpchanconn) SetWriteTimeout(nsec int64) error { - return errors.New("ssh: tcpchan: timeout not supported") +// SetWriteDeadline exists to satisfy the net.Conn interface +// but is not implemented by this type. It always returns an error. +func (t *tcpchanconn) SetWriteDeadline(deadline time.Time) error { + return errors.New("ssh: tcpchan: deadline not supported") } diff --git a/libgo/go/exp/ssh/transport.go b/libgo/go/exp/ssh/transport.go index 2e7c955..e21bc4b 100644 --- a/libgo/go/exp/ssh/transport.go +++ b/libgo/go/exp/ssh/transport.go @@ -9,6 +9,7 @@ import ( "crypto" "crypto/cipher" "crypto/hmac" + "crypto/sha1" "crypto/subtle" "errors" "hash" @@ -266,7 +267,7 @@ func (c *common) setupKeys(d direction, K, H, sessionId []byte, hashFunc crypto. generateKeyMaterial(key, d.keyTag, K, H, sessionId, h) generateKeyMaterial(macKey, d.macKeyTag, K, H, sessionId, h) - c.mac = truncatingMAC{12, hmac.NewSHA1(macKey)} + c.mac = truncatingMAC{12, hmac.New(sha1.New, macKey)} cipher, err := cipherMode.createCipher(key, iv) if err != nil { @@ -328,6 +329,8 @@ func (t truncatingMAC) Size() int { return t.length } +func (t truncatingMAC) BlockSize() int { return t.hmac.BlockSize() } + // maxVersionStringBytes is the maximum number of bytes that we'll accept as a // version string. In the event that the client is talking a different protocol // we need to set a limit otherwise we will keep using more and more memory @@ -337,7 +340,7 @@ const maxVersionStringBytes = 1024 // Read version string as specified by RFC 4253, section 4.2. func readVersion(r io.Reader) ([]byte, error) { versionString := make([]byte, 0, 64) - var ok, seenCR bool + var ok bool var buf [1]byte forEachByte: for len(versionString) < maxVersionStringBytes { @@ -345,27 +348,22 @@ forEachByte: if err != nil { return nil, err } - b := buf[0] - - if !seenCR { - if b == '\r' { - seenCR = true - } - } else { - if b == '\n' { - ok = true - break forEachByte - } else { - seenCR = false - } + // The RFC says that the version should be terminated with \r\n + // but several SSH servers actually only send a \n. + if buf[0] == '\n' { + ok = true + break forEachByte } - versionString = append(versionString, b) + versionString = append(versionString, buf[0]) } if !ok { - return nil, errors.New("failed to read version string") + return nil, errors.New("ssh: failed to read version string") } - // We need to remove the CR from versionString - return versionString[:len(versionString)-1], nil + // There might be a '\r' on the end which we should remove. + if len(versionString) > 0 && versionString[len(versionString)-1] == '\r' { + versionString = versionString[:len(versionString)-1] + } + return versionString, nil } diff --git a/libgo/go/exp/ssh/transport_test.go b/libgo/go/exp/ssh/transport_test.go index b2e2a7f..ab9177f 100644 --- a/libgo/go/exp/ssh/transport_test.go +++ b/libgo/go/exp/ssh/transport_test.go @@ -11,7 +11,7 @@ import ( ) func TestReadVersion(t *testing.T) { - buf := []byte(serverVersion) + buf := serverVersion result, err := readVersion(bufio.NewReader(bytes.NewBuffer(buf))) if err != nil { t.Errorf("readVersion didn't read version correctly: %s", err) @@ -21,6 +21,20 @@ func TestReadVersion(t *testing.T) { } } +func TestReadVersionWithJustLF(t *testing.T) { + var buf []byte + buf = append(buf, serverVersion...) + buf = buf[:len(buf)-1] + buf[len(buf)-1] = '\n' + result, err := readVersion(bufio.NewReader(bytes.NewBuffer(buf))) + if err != nil { + t.Error("readVersion failed to handle just a \n") + } + if !bytes.Equal(buf[:len(buf)-1], result) { + t.Errorf("version read did not match expected: got %x, want %x", result, buf[:len(buf)-1]) + } +} + func TestReadVersionTooLong(t *testing.T) { buf := make([]byte, maxVersionStringBytes+1) if _, err := readVersion(bufio.NewReader(bytes.NewBuffer(buf))); err == nil { @@ -29,7 +43,7 @@ func TestReadVersionTooLong(t *testing.T) { } func TestReadVersionWithoutCRLF(t *testing.T) { - buf := []byte(serverVersion) + buf := serverVersion buf = buf[:len(buf)-1] if _, err := readVersion(bufio.NewReader(bytes.NewBuffer(buf))); err == nil { t.Error("readVersion did not notice \\n was missing") diff --git a/libgo/go/exp/types/check_test.go b/libgo/go/exp/types/check_test.go index ea9218f..0e20646 100644 --- a/libgo/go/exp/types/check_test.go +++ b/libgo/go/exp/types/check_test.go @@ -47,17 +47,17 @@ var tests = []struct { var fset = token.NewFileSet() -// TODO(gri) This functionality should be in token.Fileset. -func getFile(filename string) *token.File { - for f := range fset.Files() { +func getFile(filename string) (file *token.File) { + fset.Iterate(func(f *token.File) bool { if f.Name() == filename { - return f + file = f + return false // end iteration } - } - return nil + return true + }) + return file } -// TODO(gri) This functionality should be in token.Fileset. func getPos(filename string, offset int) token.Pos { if f := getFile(filename); f != nil { return f.Pos(offset) @@ -65,8 +65,6 @@ func getPos(filename string, offset int) token.Pos { return token.NoPos } -// TODO(gri) Need to revisit parser interface. We should be able to use parser.ParseFiles -// or a similar function instead. func parseFiles(t *testing.T, testname string, filenames []string) (map[string]*ast.File, error) { files := make(map[string]*ast.File) var errors scanner.ErrorList @@ -145,8 +143,6 @@ func eliminate(t *testing.T, expected map[token.Pos]string, errors error) { for _, error := range errors.(scanner.ErrorList) { // error.Pos is a token.Position, but we want // a token.Pos so we can do a map lookup - // TODO(gri) Need to move scanner.Errors over - // to use token.Pos and file set info. pos := getPos(error.Pos.Filename, error.Pos.Offset) if msg, found := expected[pos]; found { // we expect a message at pos; check if it matches diff --git a/libgo/go/exp/types/gcimporter.go b/libgo/go/exp/types/gcimporter.go index 10c56db..a573fbb 100644 --- a/libgo/go/exp/types/gcimporter.go +++ b/libgo/go/exp/types/gcimporter.go @@ -460,29 +460,32 @@ func (p *gcParser) parseSignature() *Func { return &Func{Params: params, Results: results, IsVariadic: isVariadic} } -// MethodSpec = ( identifier | ExportedName ) Signature . +// MethodOrEmbedSpec = Name [ Signature ] . // -func (p *gcParser) parseMethodSpec() *ast.Object { - if p.tok == scanner.Ident { - p.expect(scanner.Ident) - } else { - p.parseExportedName() +func (p *gcParser) parseMethodOrEmbedSpec() *ast.Object { + p.parseName() + if p.tok == '(' { + p.parseSignature() + // TODO(gri) compute method object + return ast.NewObj(ast.Fun, "_") } - p.parseSignature() - - // TODO(gri) compute method object - return ast.NewObj(ast.Fun, "_") + // TODO lookup name and return that type + return ast.NewObj(ast.Typ, "_") } -// InterfaceType = "interface" "{" [ MethodList ] "}" . -// MethodList = MethodSpec { ";" MethodSpec } . +// InterfaceType = "interface" "{" [ MethodOrEmbedList ] "}" . +// MethodOrEmbedList = MethodOrEmbedSpec { ";" MethodOrEmbedSpec } . // func (p *gcParser) parseInterfaceType() Type { var methods ObjList parseMethod := func() { - meth := p.parseMethodSpec() - methods = append(methods, meth) + switch m := p.parseMethodOrEmbedSpec(); m.Kind { + case ast.Typ: + // TODO expand embedded methods + case ast.Fun: + methods = append(methods, m) + } } p.expectKeyword("interface") diff --git a/libgo/go/exp/utf8string/string.go b/libgo/go/exp/utf8string/string.go new file mode 100644 index 0000000..da1e2de --- /dev/null +++ b/libgo/go/exp/utf8string/string.go @@ -0,0 +1,203 @@ +// 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 utf8string provides an efficient way to index strings by rune rather than by byte. +package utf8string + +import ( + "errors" + "unicode/utf8" +) + +// String wraps a regular string with a small structure that provides more +// efficient indexing by code point index, as opposed to byte index. +// Scanning incrementally forwards or backwards is O(1) per index operation +// (although not as fast a range clause going forwards). Random access is +// O(N) in the length of the string, but the overhead is less than always +// scanning from the beginning. +// If the string is ASCII, random access is O(1). +// Unlike the built-in string type, String has internal mutable state and +// is not thread-safe. +type String struct { + str string + numRunes int + // If width > 0, the rune at runePos starts at bytePos and has the specified width. + width int + bytePos int + runePos int + nonASCII int // byte index of the first non-ASCII rune. +} + +// NewString returns a new UTF-8 string with the provided contents. +func NewString(contents string) *String { + return new(String).Init(contents) +} + +// Init initializes an existing String to hold the provided contents. +// It returns a pointer to the initialized String. +func (s *String) Init(contents string) *String { + s.str = contents + s.bytePos = 0 + s.runePos = 0 + for i := 0; i < len(contents); i++ { + if contents[i] >= utf8.RuneSelf { + // Not ASCII. + s.numRunes = utf8.RuneCountInString(contents) + _, s.width = utf8.DecodeRuneInString(contents) + s.nonASCII = i + return s + } + } + // ASCII is simple. Also, the empty string is ASCII. + s.numRunes = len(contents) + s.width = 0 + s.nonASCII = len(contents) + return s +} + +// String returns the contents of the String. This method also means the +// String is directly printable by fmt.Print. +func (s *String) String() string { + return s.str +} + +// RuneCount returns the number of runes (Unicode code points) in the String. +func (s *String) RuneCount() int { + return s.numRunes +} + +// IsASCII returns a boolean indicating whether the String contains only ASCII bytes. +func (s *String) IsASCII() bool { + return s.width == 0 +} + +// Slice returns the string sliced at rune positions [i:j]. +func (s *String) Slice(i, j int) string { + // ASCII is easy. Let the compiler catch the indexing error if there is one. + if j < s.nonASCII { + return s.str[i:j] + } + if i < 0 || j > s.numRunes || i > j { + panic(sliceOutOfRange) + } + if i == j { + return "" + } + // For non-ASCII, after At(i), bytePos is always the position of the indexed character. + var low, high int + switch { + case i < s.nonASCII: + low = i + case i == s.numRunes: + low = len(s.str) + default: + s.At(i) + low = s.bytePos + } + switch { + case j == s.numRunes: + high = len(s.str) + default: + s.At(j) + high = s.bytePos + } + return s.str[low:high] +} + +// At returns the rune with index i in the String. The sequence of runes is the same +// as iterating over the contents with a "for range" clause. +func (s *String) At(i int) rune { + // ASCII is easy. Let the compiler catch the indexing error if there is one. + if i < s.nonASCII { + return rune(s.str[i]) + } + + // Now we do need to know the index is valid. + if i < 0 || i >= s.numRunes { + panic(outOfRange) + } + + var r rune + + // Five easy common cases: within 1 spot of bytePos/runePos, or the beginning, or the end. + // With these cases, all scans from beginning or end work in O(1) time per rune. + switch { + + case i == s.runePos-1: // backing up one rune + r, s.width = utf8.DecodeLastRuneInString(s.str[0:s.bytePos]) + s.runePos = i + s.bytePos -= s.width + return r + case i == s.runePos+1: // moving ahead one rune + s.runePos = i + s.bytePos += s.width + fallthrough + case i == s.runePos: + r, s.width = utf8.DecodeRuneInString(s.str[s.bytePos:]) + return r + case i == 0: // start of string + r, s.width = utf8.DecodeRuneInString(s.str) + s.runePos = 0 + s.bytePos = 0 + return r + + case i == s.numRunes-1: // last rune in string + r, s.width = utf8.DecodeLastRuneInString(s.str) + s.runePos = i + s.bytePos = len(s.str) - s.width + return r + } + + // We need to do a linear scan. There are three places to start from: + // 1) The beginning + // 2) bytePos/runePos. + // 3) The end + // Choose the closest in rune count, scanning backwards if necessary. + forward := true + if i < s.runePos { + // Between beginning and pos. Which is closer? + // Since both i and runePos are guaranteed >= nonASCII, that's the + // lowest location we need to start from. + if i < (s.runePos-s.nonASCII)/2 { + // Scan forward from beginning + s.bytePos, s.runePos = s.nonASCII, s.nonASCII + } else { + // Scan backwards from where we are + forward = false + } + } else { + // Between pos and end. Which is closer? + if i-s.runePos < (s.numRunes-s.runePos)/2 { + // Scan forward from pos + } else { + // Scan backwards from end + s.bytePos, s.runePos = len(s.str), s.numRunes + forward = false + } + } + if forward { + // TODO: Is it much faster to use a range loop for this scan? + for { + r, s.width = utf8.DecodeRuneInString(s.str[s.bytePos:]) + if s.runePos == i { + break + } + s.runePos++ + s.bytePos += s.width + } + } else { + for { + r, s.width = utf8.DecodeLastRuneInString(s.str[0:s.bytePos]) + s.runePos-- + s.bytePos -= s.width + if s.runePos == i { + break + } + } + } + return r +} + +var outOfRange = errors.New("utf8.String: index out of range") +var sliceOutOfRange = errors.New("utf8.String: slice index out of range") diff --git a/libgo/go/exp/utf8string/string_test.go b/libgo/go/exp/utf8string/string_test.go new file mode 100644 index 0000000..28511b2 --- /dev/null +++ b/libgo/go/exp/utf8string/string_test.go @@ -0,0 +1,123 @@ +// 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 utf8string + +import ( + "math/rand" + "testing" + "unicode/utf8" +) + +var testStrings = []string{ + "", + "abcd", + "☺☻☹", + "日a本b語ç日ð本Ê語þ日¥本¼語i日©", + "日a本b語ç日ð本Ê語þ日¥本¼語i日©日a本b語ç日ð本Ê語þ日¥本¼語i日©日a本b語ç日ð本Ê語þ日¥本¼語i日©", + "\x80\x80\x80\x80", +} + +func TestScanForwards(t *testing.T) { + for _, s := range testStrings { + runes := []rune(s) + str := NewString(s) + if str.RuneCount() != len(runes) { + t.Errorf("%s: expected %d runes; got %d", s, len(runes), str.RuneCount()) + break + } + for i, expect := range runes { + got := str.At(i) + if got != expect { + t.Errorf("%s[%d]: expected %c (%U); got %c (%U)", s, i, expect, expect, got, got) + } + } + } +} + +func TestScanBackwards(t *testing.T) { + for _, s := range testStrings { + runes := []rune(s) + str := NewString(s) + if str.RuneCount() != len(runes) { + t.Errorf("%s: expected %d runes; got %d", s, len(runes), str.RuneCount()) + break + } + for i := len(runes) - 1; i >= 0; i-- { + expect := runes[i] + got := str.At(i) + if got != expect { + t.Errorf("%s[%d]: expected %c (%U); got %c (%U)", s, i, expect, expect, got, got) + } + } + } +} + +func randCount() int { + if testing.Short() { + return 100 + } + return 100000 +} + +func TestRandomAccess(t *testing.T) { + for _, s := range testStrings { + if len(s) == 0 { + continue + } + runes := []rune(s) + str := NewString(s) + if str.RuneCount() != len(runes) { + t.Errorf("%s: expected %d runes; got %d", s, len(runes), str.RuneCount()) + break + } + for j := 0; j < randCount(); j++ { + i := rand.Intn(len(runes)) + expect := runes[i] + got := str.At(i) + if got != expect { + t.Errorf("%s[%d]: expected %c (%U); got %c (%U)", s, i, expect, expect, got, got) + } + } + } +} + +func TestRandomSliceAccess(t *testing.T) { + for _, s := range testStrings { + if len(s) == 0 || s[0] == '\x80' { // the bad-UTF-8 string fools this simple test + continue + } + runes := []rune(s) + str := NewString(s) + if str.RuneCount() != len(runes) { + t.Errorf("%s: expected %d runes; got %d", s, len(runes), str.RuneCount()) + break + } + for k := 0; k < randCount(); k++ { + i := rand.Intn(len(runes)) + j := rand.Intn(len(runes) + 1) + if i > j { // include empty strings + continue + } + expect := string(runes[i:j]) + got := str.Slice(i, j) + if got != expect { + t.Errorf("%s[%d:%d]: expected %q got %q", s, i, j, expect, got) + } + } + } +} + +func TestLimitSliceAccess(t *testing.T) { + for _, s := range testStrings { + str := NewString(s) + if str.Slice(0, 0) != "" { + t.Error("failure with empty slice at beginning") + } + nr := utf8.RuneCountInString(s) + if str.Slice(nr, nr) != "" { + t.Error("failure with empty slice at end") + } + } +} diff --git a/libgo/go/fmt/fmt_test.go b/libgo/go/fmt/fmt_test.go index beb410f..504194c 100644 --- a/libgo/go/fmt/fmt_test.go +++ b/libgo/go/fmt/fmt_test.go @@ -508,27 +508,28 @@ func BenchmarkSprintfFloat(b *testing.B) { var mallocBuf bytes.Buffer +// gccgo numbers are different because gccgo does not have escape +// analysis yet. 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 %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") }}, + {5, `Sprintf("")`, func() { Sprintf("") }}, + {5, `Sprintf("xxx")`, func() { Sprintf("xxx") }}, + {5, `Sprintf("%x")`, func() { Sprintf("%x", 7) }}, + {5, `Sprintf("%s")`, func() { Sprintf("%s", "hello") }}, + {5, `Sprintf("%x %x")`, func() { Sprintf("%x %x", 7, 112) }}, + // For %g we use a float32, not float64, to guarantee passing the argument + // does not need to allocate memory to store the result in a pointer-sized word. + {20, `Sprintf("%g")`, func() { Sprintf("%g", float32(3.14159)) }}, + {5, `Fprintf(buf, "%x %x %x")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%x %x %x", 7, 8, 9) }}, + {5, `Fprintf(buf, "%s")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%s", "hello") }}, } var _ bytes.Buffer func TestCountMallocs(t *testing.T) { - if testing.Short() { - return - } for _, mt := range mallocTest { const N = 100 runtime.UpdateMemStats() @@ -538,7 +539,7 @@ func TestCountMallocs(t *testing.T) { } runtime.UpdateMemStats() mallocs += runtime.MemStats.Mallocs - if mallocs/N != uint64(mt.count) { + if mallocs/N > uint64(mt.count) { t.Errorf("%s: expected %d mallocs, got %d", mt.desc, mt.count, mallocs/N) } } diff --git a/libgo/go/go/build/path.go b/libgo/go/go/build/path.go index bb9b8ca..b86f828 100644 --- a/libgo/go/go/build/path.go +++ b/libgo/go/go/build/path.go @@ -105,14 +105,14 @@ func FindTree(path string) (tree *Tree, pkg string, err error) { continue } tree = t - pkg = path[len(tpath):] + pkg = filepath.ToSlash(path[len(tpath):]) return } err = fmt.Errorf("path %q not inside a GOPATH", path) return } tree = defaultTree - pkg = path + pkg = filepath.ToSlash(path) for _, t := range Path { if t.HasSrc(pkg) { tree = t diff --git a/libgo/go/go/build/pkgtest/sqrt_test.go b/libgo/go/go/build/pkgtest/sqrt_test.go index 95fb625..ee9fd5d 100644 --- a/libgo/go/go/build/pkgtest/sqrt_test.go +++ b/libgo/go/go/build/pkgtest/sqrt_test.go @@ -1,3 +1,7 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package pkgtest import "fmt" diff --git a/libgo/go/go/build/pkgtest/xsqrt_test.go b/libgo/go/go/build/pkgtest/xsqrt_test.go index 77e903d..3898d1d 100644 --- a/libgo/go/go/build/pkgtest/xsqrt_test.go +++ b/libgo/go/go/build/pkgtest/xsqrt_test.go @@ -1,3 +1,7 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package pkgtest_test import "pkgtest" diff --git a/libgo/go/go/doc/comment.go b/libgo/go/go/doc/comment.go index 060e37b..d73b131 100644 --- a/libgo/go/go/doc/comment.go +++ b/libgo/go/go/doc/comment.go @@ -68,7 +68,8 @@ var ( html_endp = []byte("

\n") html_pre = []byte("
")
 	html_endpre = []byte("
\n") - html_h = []byte("

") + html_h = []byte(`

`) html_endh = []byte("

\n") ) @@ -225,6 +226,12 @@ type block struct { lines []string } +var nonAlphaNumRx = regexp.MustCompile(`[^a-zA-Z0-9]`) + +func anchorID(line string) string { + return nonAlphaNumRx.ReplaceAllString(line, "_") +} + // ToHTML converts comment text to formatted HTML. // The comment was prepared by DocReader, // so it is known not to have leading, trailing blank lines @@ -253,9 +260,18 @@ func ToHTML(w io.Writer, text string, words map[string]string) { w.Write(html_endp) case opHead: w.Write(html_h) + id := "" for _, line := range b.lines { + if id == "" { + id = anchorID(line) + w.Write([]byte(id)) + w.Write(html_hq) + } commentEscape(w, line, true) } + if id == "" { + w.Write(html_hq) + } w.Write(html_endh) case opPre: w.Write(html_pre) diff --git a/libgo/go/go/doc/doc.go b/libgo/go/go/doc/doc.go index 66e2937..0259a6f 100644 --- a/libgo/go/go/doc/doc.go +++ b/libgo/go/go/doc/doc.go @@ -15,7 +15,7 @@ type Package struct { Doc string Name string ImportPath string - Imports []string // TODO(gri) this field is not computed at the moment + Imports []string Filenames []string Consts []*Value Types []*Type @@ -36,8 +36,8 @@ type Value struct { type Method struct { *Func // TODO(gri) The following fields are not set at the moment. - Recv *Type // original receiver base type - Level int // embedding level; 0 means Func is not embedded + Origin *Type // original receiver base type + Level int // embedding level; 0 means Func is not embedded } // Type is the documentation for type declaration. diff --git a/libgo/go/go/doc/doc_test.go b/libgo/go/go/doc/doc_test.go index 317d3ab..0a48301 100644 --- a/libgo/go/go/doc/doc_test.go +++ b/libgo/go/go/doc/doc_test.go @@ -6,132 +6,110 @@ package doc import ( "bytes" - "fmt" - "go/ast" + "flag" "go/parser" + "go/printer" "go/token" + "io/ioutil" + "os" + "path/filepath" + "strings" "testing" "text/template" ) -type sources map[string]string // filename -> file contents +var update = flag.Bool("update", false, "update golden (.out) files") -type testCase struct { - name string - importPath string - mode Mode - srcs sources - doc string +const dataDir = "testdata" + +var templateTxt = readTemplate("template.txt") + +func readTemplate(filename string) *template.Template { + t := template.New(filename) + t.Funcs(template.FuncMap{ + "node": nodeFmt, + "synopsis": synopsisFmt, + }) + return template.Must(t.ParseFiles(filepath.Join(dataDir, filename))) } -var tests = make(map[string]*testCase) - -// To register a new test case, use the pattern: -// -// var _ = register(&testCase{ ... }) -// -// (The result value of register is always 0 and only present to enable the pattern.) -// -func register(test *testCase) int { - if _, found := tests[test.name]; found { - panic(fmt.Sprintf("registration failed: test case %q already exists", test.name)) - } - tests[test.name] = test - return 0 +func nodeFmt(node interface{}, fset *token.FileSet) string { + var buf bytes.Buffer + printer.Fprint(&buf, fset, node) + return strings.Replace(strings.TrimSpace(buf.String()), "\n", "\n\t", -1) } -func runTest(t *testing.T, test *testCase) { - // create AST - fset := token.NewFileSet() - var pkg ast.Package - pkg.Files = make(map[string]*ast.File) - for filename, src := range test.srcs { - file, err := parser.ParseFile(fset, filename, src, parser.ParseComments) - if err != nil { - t.Errorf("test %s: %v", test.name, err) - return - } - switch { - case pkg.Name == "": - pkg.Name = file.Name.Name - case pkg.Name != file.Name.Name: - t.Errorf("test %s: different package names in test files", test.name) - return +func synopsisFmt(s string) string { + const n = 64 + if len(s) > n { + // cut off excess text and go back to a word boundary + s = s[0:n] + if i := strings.LastIndexAny(s, "\t\n "); i >= 0 { + s = s[0:i] } - pkg.Files[filename] = file + s = strings.TrimSpace(s) + " ..." } + return "// " + strings.Replace(s, "\n", " ", -1) +} - doc := New(&pkg, test.importPath, test.mode).String() - if doc != test.doc { - //TODO(gri) Enable this once the sorting issue of comments is fixed - //t.Errorf("test %s\n\tgot : %s\n\twant: %s", test.name, doc, test.doc) - } +func isGoFile(fi os.FileInfo) bool { + name := fi.Name() + return !fi.IsDir() && + len(name) > 0 && name[0] != '.' && // ignore .files + filepath.Ext(name) == ".go" +} + +type bundle struct { + *Package + FSet *token.FileSet } func Test(t *testing.T) { - for _, test := range tests { - runTest(t, test) + // get all packages + fset := token.NewFileSet() + pkgs, err := parser.ParseDir(fset, dataDir, isGoFile, parser.ParseComments) + if err != nil { + t.Fatal(err) } -} -// ---------------------------------------------------------------------------- -// Printing support + // test all packages + for _, pkg := range pkgs { + importpath := dataDir + "/" + pkg.Name + doc := New(pkg, importpath, 0) -func (pkg *Package) String() string { - var buf bytes.Buffer - docText.Execute(&buf, pkg) // ignore error - test will fail w/ incorrect output - return buf.String() -} + // golden files always use / in filenames - canonicalize them + for i, filename := range doc.Filenames { + doc.Filenames[i] = filepath.ToSlash(filename) + } + + // print documentation + var buf bytes.Buffer + if err := templateTxt.Execute(&buf, bundle{doc, fset}); err != nil { + t.Error(err) + continue + } + got := buf.Bytes() + + // update golden file if necessary + golden := filepath.Join(dataDir, pkg.Name+".out") + if *update { + err := ioutil.WriteFile(golden, got, 0644) + if err != nil { + t.Error(err) + } + continue + } -// TODO(gri) complete template -var docText = template.Must(template.New("docText").Parse( - ` -PACKAGE {{.Name}} -DOC {{printf "%q" .Doc}} -IMPORTPATH {{.ImportPath}} -FILENAMES {{.Filenames}} -`)) - -// ---------------------------------------------------------------------------- -// Test cases - -// Test that all package comments and bugs are collected, -// and that the importPath is correctly set. -// -var _ = register(&testCase{ - name: "p", - importPath: "p", - srcs: sources{ - "p1.go": "// comment 1\npackage p\n//BUG(uid): bug1", - "p0.go": "// comment 0\npackage p\n// BUG(uid): bug0", - }, - doc: ` -PACKAGE p -DOC "comment 0\n\ncomment 1\n" -IMPORTPATH p -FILENAMES [p0.go p1.go] -`, -}) - -// Test basic functionality. -// -var _ = register(&testCase{ - name: "p1", - importPath: "p", - srcs: sources{ - "p.go": ` -package p -import "a" -const pi = 3.14 // pi -type T struct{} // T -var V T // v -func F(x int) int {} // F -`, - }, - doc: ` -PACKAGE p -DOC "" -IMPORTPATH p -FILENAMES [p.go] -`, -}) + // get golden file + want, err := ioutil.ReadFile(golden) + if err != nil { + t.Error(err) + continue + } + + // compare + if bytes.Compare(got, want) != 0 { + t.Errorf("package %s\n\tgot:\n%s\n\twant:\n%s", pkg.Name, got, want) + } + } +} diff --git a/libgo/go/go/doc/exports.go b/libgo/go/go/doc/exports.go index 994bf50..a35b3e2 100644 --- a/libgo/go/go/doc/exports.go +++ b/libgo/go/go/doc/exports.go @@ -124,6 +124,9 @@ func (doc *docReader) filterType(tinfo *typeInfo, typ ast.Expr) bool { func (doc *docReader) filterSpec(spec ast.Spec) bool { switch s := spec.(type) { + case *ast.ImportSpec: + // always keep imports so we can collect them + return true case *ast.ValueSpec: s.Names = filterIdentList(s.Names) if len(s.Names) > 0 { diff --git a/libgo/go/go/doc/reader.go b/libgo/go/go/doc/reader.go index 939dd89..1a2fad5 100644 --- a/libgo/go/go/doc/reader.go +++ b/libgo/go/go/doc/reader.go @@ -9,6 +9,7 @@ import ( "go/token" "regexp" "sort" + "strconv" ) // ---------------------------------------------------------------------------- @@ -55,6 +56,7 @@ type docReader struct { doc *ast.CommentGroup // package documentation, if any pkgName string mode Mode + imports map[string]int values []*ast.GenDecl // consts and vars types map[string]*typeInfo embedded map[string]*typeInfo // embedded types, possibly not exported @@ -65,6 +67,7 @@ type docReader struct { func (doc *docReader) init(pkgName string, mode Mode) { doc.pkgName = pkgName doc.mode = mode + doc.imports = make(map[string]int) doc.types = make(map[string]*typeInfo) doc.embedded = make(map[string]*typeInfo) doc.funcs = make(map[string]*ast.FuncDecl) @@ -244,6 +247,13 @@ func (doc *docReader) addDecl(decl ast.Decl) { case *ast.GenDecl: if len(d.Specs) > 0 { switch d.Tok { + case token.IMPORT: + // imports are handled individually + for _, spec := range d.Specs { + if import_, err := strconv.Unquote(spec.(*ast.ImportSpec).Path.Value); err == nil { + doc.imports[import_] = 1 + } + } case token.CONST, token.VAR: // constants and variables are always handled as a group doc.addValue(d) @@ -346,6 +356,17 @@ func (doc *docReader) addFile(src *ast.File) { // ---------------------------------------------------------------------------- // Conversion to external representation +func (doc *docReader) makeImports() []string { + list := make([]string, len(doc.imports)) + i := 0 + for import_ := range doc.imports { + list[i] = import_ + i++ + } + sort.Strings(list) + return list +} + type sortValue []*Value func (p sortValue) Len() int { return len(p) } @@ -661,6 +682,7 @@ func (doc *docReader) newDoc(importpath string, filenames []string) *Package { // doc.funcs and thus must be called before any other // function consuming those lists p.Types = doc.makeTypes(doc.types) + p.Imports = doc.makeImports() p.Consts = makeValues(doc.values, token.CONST) p.Vars = makeValues(doc.values, token.VAR) p.Funcs = makeFuncs(doc.funcs) diff --git a/libgo/go/go/doc/testdata/a.out b/libgo/go/go/doc/testdata/a.out new file mode 100644 index 0000000..24db02d --- /dev/null +++ b/libgo/go/go/doc/testdata/a.out @@ -0,0 +1,13 @@ +// comment 0 comment 1 +PACKAGE a + +IMPORTPATH + testdata/a + +FILENAMES + testdata/a0.go + testdata/a1.go + +BUGS + // bug0 + // bug1 diff --git a/libgo/go/go/doc/testdata/a0.go b/libgo/go/go/doc/testdata/a0.go new file mode 100644 index 0000000..dc55298 --- /dev/null +++ b/libgo/go/go/doc/testdata/a0.go @@ -0,0 +1,8 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// comment 0 +package a + +//BUG(uid): bug0 diff --git a/libgo/go/go/doc/testdata/a1.go b/libgo/go/go/doc/testdata/a1.go new file mode 100644 index 0000000..098776c --- /dev/null +++ b/libgo/go/go/doc/testdata/a1.go @@ -0,0 +1,8 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// comment 1 +package a + +//BUG(uid): bug1 diff --git a/libgo/go/go/doc/testdata/b.go b/libgo/go/go/doc/testdata/b.go new file mode 100644 index 0000000..cdc77ef --- /dev/null +++ b/libgo/go/go/doc/testdata/b.go @@ -0,0 +1,13 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package b + +import "a" + +const Pi = 3.14 // Pi +var MaxInt int // MaxInt +type T struct{} // T +var V T // v +func F(x int) int {} // F diff --git a/libgo/go/go/doc/testdata/b.out b/libgo/go/go/doc/testdata/b.out new file mode 100644 index 0000000..c5ad0d0 --- /dev/null +++ b/libgo/go/go/doc/testdata/b.out @@ -0,0 +1,34 @@ +// +PACKAGE b + +IMPORTPATH + testdata/b + +IMPORTS + a + +FILENAMES + testdata/b.go + +CONSTANTS + // + const Pi = 3.14 // Pi + + +VARIABLES + // + var MaxInt int // MaxInt + + +FUNCTIONS + // + func F(x int) int + + +TYPES + // + type T struct{} // T + + // + var V T // v + diff --git a/libgo/go/go/doc/testdata/benchmark.go b/libgo/go/go/doc/testdata/benchmark.go new file mode 100644 index 0000000..0bf567b --- /dev/null +++ b/libgo/go/go/doc/testdata/benchmark.go @@ -0,0 +1,293 @@ +// 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 testing + +import ( + "flag" + "fmt" + "os" + "runtime" + "time" +) + +var matchBenchmarks = flag.String("test.bench", "", "regular expression to select benchmarks to run") +var benchTime = flag.Float64("test.benchtime", 1, "approximate run time for each benchmark, in seconds") + +// An internal type but exported because it is cross-package; part of the implementation +// of gotest. +type InternalBenchmark struct { + Name string + F func(b *B) +} + +// 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 + bytes int64 + timerOn bool + result BenchmarkResult +} + +// StartTimer starts timing a test. This function is called automatically +// before a benchmark starts, but it can also used to resume timing after +// a call to StopTimer. +func (b *B) StartTimer() { + if !b.timerOn { + b.start = time.Now() + b.timerOn = true + } +} + +// StopTimer stops timing a test. This can be used to pause the timer +// while performing complex initialization that you don't +// want to measure. +func (b *B) StopTimer() { + if b.timerOn { + b.duration += time.Now().Sub(b.start) + b.timerOn = false + } +} + +// ResetTimer sets the elapsed benchmark time to zero. +// It does not affect whether the timer is running. +func (b *B) ResetTimer() { + if b.timerOn { + b.start = time.Now() + } + b.duration = 0 +} + +// SetBytes records the number of bytes processed in a single operation. +// If this is called, the benchmark will report ns/op and MB/s. +func (b *B) SetBytes(n int64) { b.bytes = n } + +func (b *B) nsPerOp() int64 { + if b.N <= 0 { + return 0 + } + return b.duration.Nanoseconds() / int64(b.N) +} + +// runN runs a single benchmark for the specified number of iterations. +func (b *B) runN(n int) { + // Try to get a comparable environment for each run + // by clearing garbage from previous runs. + runtime.GC() + b.N = n + b.ResetTimer() + b.StartTimer() + b.benchmark.F(b) + b.StopTimer() +} + +func min(x, y int) int { + if x > y { + return y + } + return x +} + +func max(x, y int) int { + if x < y { + return y + } + return x +} + +// roundDown10 rounds a number down to the nearest power of 10. +func roundDown10(n int) int { + var tens = 0 + // tens = floor(log_10(n)) + for n > 10 { + n = n / 10 + tens++ + } + // result = 10^tens + result := 1 + for i := 0; i < tens; i++ { + result *= 10 + } + return result +} + +// roundUp rounds x up to a number of the form [1eX, 2eX, 5eX]. +func roundUp(n int) int { + base := roundDown10(n) + if n < (2 * base) { + return 2 * base + } + if n < (5 * base) { + return 5 * base + } + return 10 * base +} + +// 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 +// 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 + + // Signal that we're done whether we return normally + // or by FailNow's runtime.Goexit. + defer func() { + b.signal <- b + }() + + b.runN(n) + // Run the benchmark for at least the specified amount of time. + d := time.Duration(*benchTime * float64(time.Second)) + for !b.failed && b.duration < d && n < 1e9 { + last := n + // Predict iterations/sec. + if b.nsPerOp() == 0 { + n = 1e9 + } else { + n = int(d.Nanoseconds() / b.nsPerOp()) + } + // Run more iterations than we think we'll need for a second (1.5x). + // Don't grow too fast in case we had timing errors previously. + // Be sure to run at least one more than last time. + n = max(min(n+n/2, 100*last), last+1) + // Round up to something easy to read. + n = roundUp(n) + b.runN(n) + } + b.result = BenchmarkResult{b.N, b.duration, b.bytes} +} + +// The results of a benchmark run. +type BenchmarkResult struct { + N int // The number of iterations. + T time.Duration // The total time taken. + Bytes int64 // Bytes processed in one iteration. +} + +func (r BenchmarkResult) NsPerOp() int64 { + if r.N <= 0 { + return 0 + } + return r.T.Nanoseconds() / int64(r.N) +} + +func (r BenchmarkResult) mbPerSec() float64 { + if r.Bytes <= 0 || r.T <= 0 || r.N <= 0 { + return 0 + } + return (float64(r.Bytes) * float64(r.N) / 1e6) / r.T.Seconds() +} + +func (r BenchmarkResult) String() string { + mbs := r.mbPerSec() + mb := "" + if mbs != 0 { + mb = fmt.Sprintf("\t%7.2f MB/s", mbs) + } + nsop := r.NsPerOp() + ns := fmt.Sprintf("%10d ns/op", nsop) + if r.N > 0 && nsop < 100 { + // The format specifiers here make sure that + // the ones digits line up for all three possible formats. + if nsop < 10 { + ns = fmt.Sprintf("%13.2f ns/op", float64(r.T.Nanoseconds())/float64(r.N)) + } else { + ns = fmt.Sprintf("%12.1f ns/op", float64(r.T.Nanoseconds())/float64(r.N)) + } + } + return fmt.Sprintf("%8d\t%s%s", r.N, ns, mb) +} + +// An internal function but exported because it is cross-package; part of the implementation +// of gotest. +func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks []InternalBenchmark) { + // If no flag was specified, don't run benchmarks. + if len(*matchBenchmarks) == 0 { + return + } + for _, Benchmark := range benchmarks { + matched, err := matchString(*matchBenchmarks, Benchmark.Name) + if err != nil { + fmt.Fprintf(os.Stderr, "testing: invalid regexp for -test.bench: %s\n", err) + os.Exit(1) + } + if !matched { + continue + } + for _, procs := range cpuList { + runtime.GOMAXPROCS(procs) + 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) + } + } + } +} + +// 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{ + common: common{ + signal: make(chan interface{}), + }, + benchmark: InternalBenchmark{"", f}, + } + return b.run() +} diff --git a/libgo/go/go/doc/testdata/example.go b/libgo/go/go/doc/testdata/example.go new file mode 100644 index 0000000..fdeda13 --- /dev/null +++ b/libgo/go/go/doc/testdata/example.go @@ -0,0 +1,81 @@ +// 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 testing + +import ( + "bytes" + "fmt" + "io" + "os" + "strings" + "time" +) + +type InternalExample struct { + Name string + F func() + Output string +} + +func RunExamples(examples []InternalExample) (ok bool) { + ok = true + + var eg InternalExample + + stdout, stderr := os.Stdout, os.Stderr + defer func() { + os.Stdout, os.Stderr = stdout, stderr + if e := recover(); e != nil { + fmt.Printf("--- FAIL: %s\npanic: %v\n", eg.Name, e) + os.Exit(1) + } + }() + + for _, eg = range examples { + if *chatty { + fmt.Printf("=== RUN: %s\n", eg.Name) + } + + // capture stdout and stderr + r, w, err := os.Pipe() + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + os.Stdout, os.Stderr = w, w + outC := make(chan string) + go func() { + buf := new(bytes.Buffer) + _, err := io.Copy(buf, r) + if err != nil { + fmt.Fprintf(stderr, "testing: copying pipe: %v\n", err) + os.Exit(1) + } + outC <- buf.String() + }() + + // run example + t0 := time.Now() + eg.F() + dt := time.Now().Sub(t0) + + // close pipe, restore stdout/stderr, get output + w.Close() + os.Stdout, os.Stderr = stdout, stderr + out := <-outC + + // report any errors + tstr := fmt.Sprintf("(%.2f seconds)", dt.Seconds()) + 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) + } + } + + return +} diff --git a/libgo/go/go/doc/testdata/template.txt b/libgo/go/go/doc/testdata/template.txt new file mode 100644 index 0000000..32e331c --- /dev/null +++ b/libgo/go/go/doc/testdata/template.txt @@ -0,0 +1,65 @@ +{{synopsis .Doc}} +PACKAGE {{.Name}} + +IMPORTPATH + {{.ImportPath}} + +{{with .Imports}}IMPORTS +{{range .}} {{.}} +{{end}} +{{end}}{{/* + +*/}}FILENAMES +{{range .Filenames}} {{.}} +{{end}}{{/* + +*/}}{{with .Consts}} +CONSTANTS +{{range .}} {{synopsis .Doc}} + {{node .Decl $.FSet}} + +{{end}}{{end}}{{/* + +*/}}{{with .Vars}} +VARIABLES +{{range .}} {{synopsis .Doc}} + {{node .Decl $.FSet}} + +{{end}}{{end}}{{/* + +*/}}{{with .Funcs}} +FUNCTIONS +{{range .}} {{synopsis .Doc}} + {{node .Decl $.FSet}} + +{{end}}{{end}}{{/* + +*/}}{{with .Types}} +TYPES +{{range .}} {{synopsis .Doc}} + {{node .Decl $.FSet}} + +{{range .Consts}} {{synopsis .Doc}} + {{node .Decl $.FSet}} + +{{end}}{{/* + +*/}}{{range .Vars}} {{synopsis .Doc}} + {{node .Decl $.FSet}} + +{{end}}{{/* + +*/}}{{range .Funcs}} {{synopsis .Doc}} + {{node .Decl $.FSet}} + +{{end}}{{/* + +*/}}{{range .Methods}} {{synopsis .Doc}} + {{node .Decl $.FSet}} + +{{end}}{{end}}{{end}}{{/* + +*/}}{{with .Bugs}} +BUGS +{{range .}} {{synopsis .}} +{{end}}{{end}} \ No newline at end of file diff --git a/libgo/go/go/doc/testdata/testing.go b/libgo/go/go/doc/testdata/testing.go new file mode 100644 index 0000000..cfe212d --- /dev/null +++ b/libgo/go/go/doc/testdata/testing.go @@ -0,0 +1,404 @@ +// 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 testing provides support for automated testing of Go packages. +// It is intended to be used in concert with the ``gotest'' utility, which automates +// execution of any function of the form +// func TestXxx(*testing.T) +// where Xxx can be any alphanumeric string (but the first letter must not be in +// [a-z]) and serves to identify the test routine. +// These TestXxx routines should be declared within the package they are testing. +// +// Functions of the form +// func BenchmarkXxx(*testing.B) +// are considered benchmarks, and are executed by gotest when the -test.bench +// flag is provided. +// +// A sample benchmark function looks like this: +// func BenchmarkHello(b *testing.B) { +// for i := 0; i < b.N; i++ { +// fmt.Sprintf("hello") +// } +// } +// The benchmark package will vary b.N until the benchmark function lasts +// long enough to be timed reliably. The output +// 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: +// func BenchmarkBigLen(b *testing.B) { +// b.StopTimer() +// big := NewBig() +// b.StartTimer() +// for i := 0; i < b.N; i++ { +// big.Len() +// } +// } +package testing + +import ( + "flag" + "fmt" + "os" + "runtime" + "runtime/pprof" + "strconv" + "strings" + "time" +) + +var ( + // The short flag requests that tests run more quickly, but its functionality + // is provided by test writers themselves. The testing package is just its + // home. The all.bash installation script sets it to make installation more + // efficient, but by default the flag is off so a plain "gotest" will do a + // full test of the package. + short = flag.Bool("test.short", false, "run smaller test suite to save time") + + // Report as tests are run; default is silent for success. + chatty = flag.Bool("test.v", false, "verbose: print additional output") + match = flag.String("test.run", "", "regular expression to select tests to run") + memProfile = flag.String("test.memprofile", "", "write a memory profile to the named file after execution") + memProfileRate = flag.Int("test.memprofilerate", 0, "if >=0, sets runtime.MemProfileRate") + cpuProfile = flag.String("test.cpuprofile", "", "write a cpu profile to the named file during execution") + timeout = flag.Duration("test.timeout", 0, "if positive, sets an aggregate time limit for all tests") + cpuListStr = flag.String("test.cpu", "", "comma-separated list of number of CPUs to use for each test") + parallel = flag.Int("test.parallel", runtime.GOMAXPROCS(0), "maximum test parallelism") + + 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 +} + +// decorate inserts the final newline if needed and indentation tabs for formatting. +// If addFileLine is true, it also prefixes the string with the file and line of the call site. +func decorate(s string, addFileLine bool) string { + if addFileLine { + _, file, line, ok := runtime.Caller(3) // decorate + log + public function. + if ok { + // Truncate file name at last file name separator. + if index := strings.LastIndex(file, "/"); index >= 0 { + file = file[index+1:] + } else if index = strings.LastIndex(file, "\\"); index >= 0 { + file = file[index+1:] + } + } else { + file = "???" + line = 1 + } + s = fmt.Sprintf("%s:%d: %s", file, line, s) + } + s = "\t" + s // Every line is indented at least one tab. + n := len(s) + if n > 0 && s[n-1] != '\n' { + s += "\n" + n++ + } + for i := 0; i < n-1; i++ { // -1 to avoid final newline + if s[i] == '\n' { + // Second and subsequent lines are indented an extra tab. + return s[0:i+1] + "\t" + decorate(s[i+1:n], false) + } + } + return s +} + +// 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 { + common + name string // Name of test. + startParallel chan bool // Parallel tests will wait on this. +} + +// Fail marks the function as having failed but continues execution. +func (c *common) Fail() { c.failed = true } + +// Failed returns whether the function has failed. +func (c *common) Failed() bool { return c.failed } + +// FailNow marks the function as having failed and stops its execution. +// Execution will continue at the next Test. +func (c *common) FailNow() { + c.Fail() + + // Calling runtime.Goexit will exit the goroutine, which + // will run the deferred functions in this goroutine, + // which will eventually run the deferred lines in tRunner, + // which will signal to the test loop that this test is done. + // + // A previous version of this code said: + // + // c.duration = ... + // c.signal <- c.self + // runtime.Goexit() + // + // This previous version duplicated code (those lines are in + // tRunner no matter what), but worse the goroutine teardown + // implicit in runtime.Goexit was not guaranteed to complete + // before the test exited. If a test deferred an important cleanup + // function (like removing temporary files), there was no guarantee + // it would run on a test failure. Because we send on c.signal during + // a top-of-stack deferred function now, we know that the send + // only happens after any other stacked defers have completed. + runtime.Goexit() +} + +// log generates the output. It's always at the same stack depth. +func (c *common) log(s string) { + c.output = append(c.output, decorate(s, true)...) +} + +// Log formats its arguments using default formatting, analogous to Println(), +// and records the text in the error log. +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 (c *common) Logf(format string, args ...interface{}) { c.log(fmt.Sprintf(format, args...)) } + +// Error is equivalent to Log() followed by Fail(). +func (c *common) Error(args ...interface{}) { + c.log(fmt.Sprintln(args...)) + c.Fail() +} + +// Errorf is equivalent to Logf() followed by 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 (c *common) Fatal(args ...interface{}) { + c.log(fmt.Sprintln(args...)) + c.FailNow() +} + +// Fatalf is equivalent to Logf() followed by 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.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 +// of gotest. +type InternalTest struct { + Name string + F func(*T) +} + +func tRunner(t *T, test *InternalTest) { + t.start = time.Now() + + // When this goroutine is done, either because test.F(t) + // returned normally or because a test failure triggered + // a call to runtime.Goexit, record the duration and send + // a signal saying that the test is done. + defer func() { + t.duration = time.Now().Sub(t.start) + t.signal <- t + }() + + test.F(t) +} + +// An internal function but exported because it is cross-package; part of the implementation +// of gotest. +func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) { + flag.Parse() + parseCpuList() + + before() + startAlarm() + testOk := RunTests(matchString, tests) + exampleOk := RunExamples(examples) + if !testOk || !exampleOk { + fmt.Println("FAIL") + os.Exit(1) + } + fmt.Println("PASS") + stopAlarm() + RunBenchmarks(matchString, benchmarks) + after() +} + +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.output) + } else if *chatty { + fmt.Printf(format, "PASS", t.name, tstr, t.output) + } +} + +func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool) { + ok = true + if len(tests) == 0 { + fmt.Fprintln(os.Stderr, "testing: warning: no tests to run") + return + } + 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) + + for i := 0; i < len(tests); i++ { + matched, err := matchString(*match, tests[i].Name) + if err != nil { + fmt.Fprintf(os.Stderr, "testing: invalid regexp for -test.run: %s\n", err) + os.Exit(1) + } + if !matched { + continue + } + testName := tests[i].Name + if procs != 1 { + testName = fmt.Sprintf("%s-%d", tests[i].Name, procs) + } + 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.signal).(*T) + if out == nil { // Parallel run. + go func() { + collector <- <-t.signal + }() + numParallel++ + continue + } + t.report() + ok = ok && !out.failed + } + + running := 0 + for numParallel+running > 0 { + if running < *parallel && numParallel > 0 { + startParallel <- true + running++ + numParallel-- + continue + } + t := (<-collector).(*T) + t.report() + ok = ok && !t.failed + running-- + } + } + return +} + +// before runs before all testing. +func before() { + if *memProfileRate > 0 { + runtime.MemProfileRate = *memProfileRate + } + if *cpuProfile != "" { + f, err := os.Create(*cpuProfile) + if err != nil { + fmt.Fprintf(os.Stderr, "testing: %s", err) + return + } + if err := pprof.StartCPUProfile(f); err != nil { + fmt.Fprintf(os.Stderr, "testing: can't start cpu profile: %s", err) + f.Close() + return + } + // Could save f so after can call f.Close; not worth the effort. + } + +} + +// after runs after all testing. +func after() { + if *cpuProfile != "" { + pprof.StopCPUProfile() // flushes profile to disk + } + if *memProfile != "" { + f, err := os.Create(*memProfile) + if err != nil { + fmt.Fprintf(os.Stderr, "testing: %s", err) + return + } + if err = pprof.WriteHeapProfile(f); err != nil { + fmt.Fprintf(os.Stderr, "testing: can't write %s: %s", *memProfile, err) + } + f.Close() + } +} + +var timer *time.Timer + +// startAlarm starts an alarm if requested. +func startAlarm() { + if *timeout > 0 { + timer = time.AfterFunc(*timeout, alarm) + } +} + +// stopAlarm turns off the alarm. +func stopAlarm() { + if *timeout > 0 { + timer.Stop() + } +} + +// alarm is called if the timeout expires. +func alarm() { + panic("test timed out") +} + +func parseCpuList() { + if len(*cpuListStr) == 0 { + cpuList = append(cpuList, runtime.GOMAXPROCS(-1)) + } else { + for _, val := range strings.Split(*cpuListStr, ",") { + cpu, err := strconv.Atoi(val) + if err != nil || cpu <= 0 { + fmt.Fprintf(os.Stderr, "testing: invalid value %q for -test.cpu", val) + os.Exit(1) + } + cpuList = append(cpuList, cpu) + } + } +} diff --git a/libgo/go/go/doc/testdata/testing.out b/libgo/go/go/doc/testdata/testing.out new file mode 100644 index 0000000..15a9039 --- /dev/null +++ b/libgo/go/go/doc/testdata/testing.out @@ -0,0 +1,156 @@ +// Package testing provides support for automated testing of Go ... +PACKAGE testing + +IMPORTPATH + testdata/testing + +IMPORTS + bytes + flag + fmt + io + os + runtime + runtime/pprof + strconv + strings + time + +FILENAMES + testdata/benchmark.go + testdata/example.go + testdata/testing.go + +FUNCTIONS + // An internal function but exported because it is cross-package; ... + func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) + + // An internal function but exported because it is cross-package; ... + func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks []InternalBenchmark) + + // + func RunExamples(examples []InternalExample) (ok bool) + + // + func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool) + + // Short reports whether the -test.short flag is set. + func Short() bool + + +TYPES + // B is a type passed to Benchmark functions to manage benchmark ... + type B struct { + N int + // contains filtered or unexported fields + } + + // Error is equivalent to Log() followed by Fail(). + func (c *B) Error(args ...interface{}) + + // Errorf is equivalent to Logf() followed by Fail(). + func (c *B) Errorf(format string, args ...interface{}) + + // Fail marks the function as having failed but continues ... + func (c *B) Fail() + + // FailNow marks the function as having failed and stops its ... + func (c *B) FailNow() + + // Failed returns whether the function has failed. + func (c *B) Failed() bool + + // Fatal is equivalent to Log() followed by FailNow(). + func (c *B) Fatal(args ...interface{}) + + // Fatalf is equivalent to Logf() followed by FailNow(). + func (c *B) Fatalf(format string, args ...interface{}) + + // Log formats its arguments using default formatting, analogous ... + func (c *B) Log(args ...interface{}) + + // Logf formats its arguments according to the format, analogous ... + func (c *B) Logf(format string, args ...interface{}) + + // ResetTimer sets the elapsed benchmark time to zero. It does not ... + func (b *B) ResetTimer() + + // SetBytes records the number of bytes processed in a single ... + func (b *B) SetBytes(n int64) + + // StartTimer starts timing a test. This function is called ... + func (b *B) StartTimer() + + // StopTimer stops timing a test. This can be used to pause the ... + func (b *B) StopTimer() + + // The results of a benchmark run. + type BenchmarkResult struct { + N int // The number of iterations. + T time.Duration // The total time taken. + Bytes int64 // Bytes processed in one iteration. + } + + // Benchmark benchmarks a single function. Useful for creating ... + func Benchmark(f func(b *B)) BenchmarkResult + + // + func (r BenchmarkResult) NsPerOp() int64 + + // + func (r BenchmarkResult) String() string + + // An internal type but exported because it is cross-package; part ... + type InternalBenchmark struct { + Name string + F func(b *B) + } + + // + type InternalExample struct { + Name string + F func() + Output string + } + + // An internal type but exported because it is cross-package; part ... + type InternalTest struct { + Name string + F func(*T) + } + + // T is a type passed to Test functions to manage test state and ... + type T struct { + // contains filtered or unexported fields + } + + // Error is equivalent to Log() followed by Fail(). + func (c *T) Error(args ...interface{}) + + // Errorf is equivalent to Logf() followed by Fail(). + func (c *T) Errorf(format string, args ...interface{}) + + // Fail marks the function as having failed but continues ... + func (c *T) Fail() + + // FailNow marks the function as having failed and stops its ... + func (c *T) FailNow() + + // Failed returns whether the function has failed. + func (c *T) Failed() bool + + // Fatal is equivalent to Log() followed by FailNow(). + func (c *T) Fatal(args ...interface{}) + + // Fatalf is equivalent to Logf() followed by FailNow(). + func (c *T) Fatalf(format string, args ...interface{}) + + // Log formats its arguments using default formatting, analogous ... + func (c *T) Log(args ...interface{}) + + // Logf formats its arguments according to the format, analogous ... + func (c *T) Logf(format string, args ...interface{}) + + // Parallel signals that this test is to be run in parallel with ... + func (t *T) Parallel() + diff --git a/libgo/go/go/parser/interface.go b/libgo/go/go/parser/interface.go index 2ce3df8..4b72f385 100644 --- a/libgo/go/go/parser/interface.go +++ b/libgo/go/go/parser/interface.go @@ -135,8 +135,10 @@ func ParseDir(fset *token.FileSet, path string, filter func(os.FileInfo) bool, m // func ParseExpr(x string) (ast.Expr, error) { // parse x within the context of a complete package for correct scopes; - // use //line directive for correct positions in error messages - file, err := ParseFile(token.NewFileSet(), "", "package p;func _(){_=\n//line :1\n"+x+";}", 0) + // use //line directive for correct positions in error messages and put + // x alone on a separate line (handles line comments), followed by a ';' + // to force an error if the expression is incomplete + file, err := ParseFile(token.NewFileSet(), "", "package p;func _(){_=\n//line :1\n"+x+"\n;}", 0) if err != nil { return nil, err } diff --git a/libgo/go/go/scanner/scanner.go b/libgo/go/go/scanner/scanner.go index 59a7965..05665b2 100644 --- a/libgo/go/go/scanner/scanner.go +++ b/libgo/go/go/scanner/scanner.go @@ -6,7 +6,7 @@ // source which can then be tokenized through repeated calls to the Scan // function. Typical use: // -// var s Scanner +// var s scanner.Scanner // fset := token.NewFileSet() // position information is relative to fset // file := fset.AddFile(filename, fset.Base(), len(src)) // register file // s.Init(file, src, nil /* no error handler */, 0) diff --git a/libgo/go/go/token/position.go b/libgo/go/go/token/position.go index 8cf3dcd..647d1b7 100644 --- a/libgo/go/go/token/position.go +++ b/libgo/go/go/token/position.go @@ -12,6 +12,9 @@ import ( "sync" ) +// ----------------------------------------------------------------------------- +// Positions + // Position describes an arbitrary source position // including the file, line, and column location. // A Position is valid if the line number is > 0. @@ -81,84 +84,8 @@ func (p Pos) IsValid() bool { return p != NoPos } -func searchFiles(a []*File, x int) int { - return sort.Search(len(a), func(i int) bool { return a[i].base > x }) - 1 -} - -func (s *FileSet) file(p Pos) *File { - // common case: p is in last file touched - if f := s.last; f != nil && f.base <= int(p) && int(p) <= f.base+f.size { - return f - } - // p is not in last file touched - search all files - if i := searchFiles(s.files, int(p)); i >= 0 { - f := s.files[i] - // f.base <= int(p) by definition of searchFiles - if int(p) <= f.base+f.size { - s.last = f - return f - } - } - return nil -} - -// File returns the file which contains the position p. -// If no such file is found (for instance for p == NoPos), -// the result is nil. -// -func (s *FileSet) File(p Pos) (f *File) { - if p != NoPos { - s.mutex.RLock() - f = s.file(p) - s.mutex.RUnlock() - } - return -} - -func (f *File) position(p Pos) (pos Position) { - offset := int(p) - f.base - pos.Offset = offset - pos.Filename, pos.Line, pos.Column = f.info(offset) - return -} - -// Position converts a Pos in the fileset into a general Position. -func (s *FileSet) Position(p Pos) (pos Position) { - if p != NoPos { - s.mutex.RLock() - if f := s.file(p); f != nil { - pos = f.position(p) - } - s.mutex.RUnlock() - } - return -} - -// A lineInfo object describes alternative file and line number -// information (such as provided via a //line comment in a .go -// file) for a given file offset. -type lineInfo struct { - // fields are exported to make them accessible to gob - Offset int - Filename string - Line int -} - -// AddLineInfo adds alternative file and line number information for -// a given file offset. The offset must be larger than the offset for -// the previously added alternative line info and smaller than the -// file size; otherwise the information is ignored. -// -// AddLineInfo is typically used to register alternative position -// information for //line filename:line comments in source files. -// -func (f *File) AddLineInfo(offset int, filename string, line int) { - f.set.mutex.Lock() - if i := len(f.infos); i == 0 || f.infos[i-1].Offset < offset && offset < f.size { - f.infos = append(f.infos, lineInfo{offset, filename, line}) - } - f.set.mutex.Unlock() -} +// ----------------------------------------------------------------------------- +// File // A File is a handle for a file belonging to a FileSet. // A File has a name, size, and line offset table. @@ -253,6 +180,32 @@ func (f *File) SetLinesForContent(content []byte) { f.set.mutex.Unlock() } +// A lineInfo object describes alternative file and line number +// information (such as provided via a //line comment in a .go +// file) for a given file offset. +type lineInfo struct { + // fields are exported to make them accessible to gob + Offset int + Filename string + Line int +} + +// AddLineInfo adds alternative file and line number information for +// a given file offset. The offset must be larger than the offset for +// the previously added alternative line info and smaller than the +// file size; otherwise the information is ignored. +// +// AddLineInfo is typically used to register alternative position +// information for //line filename:line comments in source files. +// +func (f *File) AddLineInfo(offset int, filename string, line int) { + f.set.mutex.Lock() + if i := len(f.infos); i == 0 || f.infos[i-1].Offset < offset && offset < f.size { + f.infos = append(f.infos, lineInfo{offset, filename, line}) + } + f.set.mutex.Unlock() +} + // Pos returns the Pos value for the given file offset; // the offset must be <= f.Size(). // f.Pos(f.Offset(p)) == p. @@ -283,41 +236,6 @@ func (f *File) Line(p Pos) int { return f.Position(p).Line } -// Position returns the Position value for the given file position p; -// p must be a Pos value in that file or NoPos. -// -func (f *File) Position(p Pos) (pos Position) { - if p != NoPos { - if int(p) < f.base || int(p) > f.base+f.size { - panic("illegal Pos value") - } - pos = f.position(p) - } - return -} - -func searchInts(a []int, x int) int { - // This function body is a manually inlined version of: - // - // return sort.Search(len(a), func(i int) bool { return a[i] > x }) - 1 - // - // With better compiler optimizations, this may not be needed in the - // future, but at the moment this change improves the go/printer - // benchmark performance by ~30%. This has a direct impact on the - // speed of gofmt and thus seems worthwhile (2011-04-29). - i, j := 0, len(a) - for i < j { - h := i + (j-i)/2 // avoid overflow when computing h - // i ≤ h < j - if a[h] <= x { - i = h + 1 - } else { - j = h - } - } - return i - 1 -} - func searchLineInfos(a []lineInfo, x int) int { return sort.Search(len(a), func(i int) bool { return a[i].Offset > x }) - 1 } @@ -341,6 +259,29 @@ func (f *File) info(offset int) (filename string, line, column int) { return } +func (f *File) position(p Pos) (pos Position) { + offset := int(p) - f.base + pos.Offset = offset + pos.Filename, pos.Line, pos.Column = f.info(offset) + return +} + +// Position returns the Position value for the given file position p; +// p must be a Pos value in that file or NoPos. +// +func (f *File) Position(p Pos) (pos Position) { + if p != NoPos { + if int(p) < f.base || int(p) > f.base+f.size { + panic("illegal Pos value") + } + pos = f.position(p) + } + return +} + +// ----------------------------------------------------------------------------- +// FileSet + // A FileSet represents a set of source files. // Methods of file sets are synchronized; multiple goroutines // may invoke them concurrently. @@ -404,23 +345,91 @@ func (s *FileSet) AddFile(filename string, base, size int) *File { return f } -// Files returns the files added to the file set. -func (s *FileSet) Files() <-chan *File { - ch := make(chan *File) - go func() { - for i := 0; ; i++ { - var f *File - s.mutex.RLock() - if i < len(s.files) { - f = s.files[i] - } - s.mutex.RUnlock() - if f == nil { - break - } - ch <- f +// Iterate calls f for the files in the file set in the order they were added +// until f returns false. +// +func (s *FileSet) Iterate(f func(*File) bool) { + for i := 0; ; i++ { + var file *File + s.mutex.RLock() + if i < len(s.files) { + file = s.files[i] + } + s.mutex.RUnlock() + if file == nil || !f(file) { + break } - close(ch) - }() - return ch + } +} + +func searchFiles(a []*File, x int) int { + return sort.Search(len(a), func(i int) bool { return a[i].base > x }) - 1 +} + +func (s *FileSet) file(p Pos) *File { + // common case: p is in last file + if f := s.last; f != nil && f.base <= int(p) && int(p) <= f.base+f.size { + return f + } + // p is not in last file - search all files + if i := searchFiles(s.files, int(p)); i >= 0 { + f := s.files[i] + // f.base <= int(p) by definition of searchFiles + if int(p) <= f.base+f.size { + s.last = f + return f + } + } + return nil +} + +// File returns the file that contains the position p. +// If no such file is found (for instance for p == NoPos), +// the result is nil. +// +func (s *FileSet) File(p Pos) (f *File) { + if p != NoPos { + s.mutex.RLock() + f = s.file(p) + s.mutex.RUnlock() + } + return +} + +// Position converts a Pos in the fileset into a general Position. +func (s *FileSet) Position(p Pos) (pos Position) { + if p != NoPos { + s.mutex.RLock() + if f := s.file(p); f != nil { + pos = f.position(p) + } + s.mutex.RUnlock() + } + return +} + +// ----------------------------------------------------------------------------- +// Helper functions + +func searchInts(a []int, x int) int { + // This function body is a manually inlined version of: + // + // return sort.Search(len(a), func(i int) bool { return a[i] > x }) - 1 + // + // With better compiler optimizations, this may not be needed in the + // future, but at the moment this change improves the go/printer + // benchmark performance by ~30%. This has a direct impact on the + // speed of gofmt and thus seems worthwhile (2011-04-29). + // TODO(gri): Remove this when compilers have caught up. + i, j := 0, len(a) + for i < j { + h := i + (j-i)/2 // avoid overflow when computing h + // i ≤ h < j + if a[h] <= x { + i = h + 1 + } else { + j = h + } + } + return i - 1 } diff --git a/libgo/go/go/token/position_test.go b/libgo/go/go/token/position_test.go index 30bec59..160107d 100644 --- a/libgo/go/go/token/position_test.go +++ b/libgo/go/go/token/position_test.go @@ -167,12 +167,13 @@ func TestFiles(t *testing.T) { for i, test := range tests { fset.AddFile(test.filename, fset.Base(), test.size) j := 0 - for g := range fset.Files() { - if g.Name() != tests[j].filename { - t.Errorf("expected filename = %s; got %s", tests[j].filename, g.Name()) + fset.Iterate(func(f *File) bool { + if f.Name() != tests[j].filename { + t.Errorf("expected filename = %s; got %s", tests[j].filename, f.Name()) } j++ - } + return true + }) if j != i+1 { t.Errorf("expected %d files; got %d", i+1, j) } diff --git a/libgo/go/hash/adler32/adler32.go b/libgo/go/hash/adler32/adler32.go index 8103a89..64fe68c 100644 --- a/libgo/go/hash/adler32/adler32.go +++ b/libgo/go/hash/adler32/adler32.go @@ -38,6 +38,8 @@ func New() hash.Hash32 { func (d *digest) Size() int { return Size } +func (d *digest) BlockSize() int { return 1 } + // Add p to the running checksum a, b. func update(a, b uint32, p []byte) (aa, bb uint32) { for _, pi := range p { diff --git a/libgo/go/hash/crc32/crc32.go b/libgo/go/hash/crc32/crc32.go index 557fab8..236d778 100644 --- a/libgo/go/hash/crc32/crc32.go +++ b/libgo/go/hash/crc32/crc32.go @@ -94,6 +94,8 @@ func NewIEEE() hash.Hash32 { return New(IEEETable) } func (d *digest) Size() int { return Size } +func (d *digest) BlockSize() int { return 1 } + func (d *digest) Reset() { d.crc = 0 } func update(crc uint32, tab *Table, p []byte) uint32 { diff --git a/libgo/go/hash/crc64/crc64.go b/libgo/go/hash/crc64/crc64.go index e5c1db4..5b64390 100644 --- a/libgo/go/hash/crc64/crc64.go +++ b/libgo/go/hash/crc64/crc64.go @@ -53,6 +53,8 @@ func New(tab *Table) hash.Hash64 { return &digest{0, tab} } func (d *digest) Size() int { return Size } +func (d *digest) BlockSize() int { return 1 } + func (d *digest) Reset() { d.crc = 0 } func update(crc uint64, tab *Table, p []byte) uint64 { diff --git a/libgo/go/hash/fnv/fnv.go b/libgo/go/hash/fnv/fnv.go index 2c8a251..ea50198 100644 --- a/libgo/go/hash/fnv/fnv.go +++ b/libgo/go/hash/fnv/fnv.go @@ -104,6 +104,11 @@ func (s *sum32a) Size() int { return 4 } func (s *sum64) Size() int { return 8 } func (s *sum64a) Size() int { return 8 } +func (s *sum32) BlockSize() int { return 1 } +func (s *sum32a) BlockSize() int { return 1 } +func (s *sum64) BlockSize() int { return 1 } +func (s *sum64a) BlockSize() int { return 1 } + func (s *sum32) Sum(in []byte) []byte { v := uint32(*s) in = append(in, byte(v>>24)) diff --git a/libgo/go/hash/hash.go b/libgo/go/hash/hash.go index 8598f4e..aa895cf 100644 --- a/libgo/go/hash/hash.go +++ b/libgo/go/hash/hash.go @@ -22,6 +22,12 @@ type Hash interface { // Size returns the number of bytes Sum will return. Size() int + + // BlockSize returns the hash's underlying block size. + // The Write method must be able to accept any amount + // of data, but it may operate more efficiently if all writes + // are a multiple of the block size. + BlockSize() int } // Hash32 is the common interface implemented by all 32-bit hash functions. diff --git a/libgo/go/html/parse.go b/libgo/go/html/parse.go index 43c0472..04f4ae7 100644 --- a/libgo/go/html/parse.go +++ b/libgo/go/html/parse.go @@ -1713,8 +1713,8 @@ func parseForeignContent(p *parser) bool { } if breakout[p.tok.Data] { for i := len(p.oe) - 1; i >= 0; i-- { - // TODO: HTML, MathML integration points. - if p.oe[i].Namespace == "" { + // TODO: MathML integration points. + if p.oe[i].Namespace == "" || htmlIntegrationPoint(p.oe[i]) { p.oe = p.oe[:i+1] break } diff --git a/libgo/go/html/parse_test.go b/libgo/go/html/parse_test.go index c929c25..1528dff 100644 --- a/libgo/go/html/parse_test.go +++ b/libgo/go/html/parse_test.go @@ -184,7 +184,7 @@ func TestParser(t *testing.T) { {"tests4.dat", -1}, {"tests5.dat", -1}, {"tests6.dat", -1}, - {"tests10.dat", 33}, + {"tests10.dat", 35}, } for _, tf := range testFiles { f, err := os.Open("testdata/webkit/" + tf.filename) diff --git a/libgo/go/html/template/doc.go b/libgo/go/html/template/doc.go index fc0e382..77a9bf2 100644 --- a/libgo/go/html/template/doc.go +++ b/libgo/go/html/template/doc.go @@ -31,8 +31,8 @@ Example import "text/template" ... - t, err := (&template.Set{}).Parse(`{{define "T"}}Hello, {{.}}!{{end}}`) - err = t.Execute(out, "T", "") + t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`) + err = t.ExecuteTemplate(out, "T", "") produces @@ -42,12 +42,12 @@ but with contextual autoescaping, import "html/template" ... - t, err := (&template.Set{}).Parse(`{{define "T"}}Hello, {{.}}!{{end}}`) - err = t.Execute(out, "T", "") + t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`) + err = t.ExecuteTemplate(out, "T", "") produces safe, escaped HTML output - Hello, <script>alert('you have been pwned')</script>! + Hello, <script>alert('you have been pwned')</script>! Contexts @@ -57,8 +57,8 @@ functions to each simple action pipeline, so given the excerpt {{.}} -At parse time each {{.}} is overwritten to add escaping functions as necessary, -in this case, +At parse time each {{.}} is overwritten to add escaping functions as necessary. +In this case it becomes {{. | html}} diff --git a/libgo/go/html/template/escape_test.go b/libgo/go/html/template/escape_test.go index 2ce1fb5..0e31674 100644 --- a/libgo/go/html/template/escape_test.go +++ b/libgo/go/html/template/escape_test.go @@ -899,7 +899,7 @@ func TestErrors(t *testing.T) { }, { ``, - "z:1: (action: [(command: [F=[H]])]) appears in an ambiguous URL context", + "z:1: {{.H}} appears in an ambiguous URL context", }, { `> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)} -}) +} -// RGBAModel is the Model for RGBA64 colors. -var RGBA64Model Model = ModelFunc(func(c Color) Color { +func rgba64Model(c Color) Color { if _, ok := c.(RGBA64); ok { return c } r, g, b, a := c.RGBA() return RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)} -}) +} -// NRGBAModel is the Model for NRGBA colors. -var NRGBAModel Model = ModelFunc(func(c Color) Color { +func nrgbaModel(c Color) Color { if _, ok := c.(NRGBA); ok { return c } @@ -187,10 +196,9 @@ var NRGBAModel Model = ModelFunc(func(c Color) Color { g = (g * 0xffff) / a b = (b * 0xffff) / a return NRGBA{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)} -}) +} -// NRGBAModel is the Model for NRGBA64 colors. -var NRGBA64Model Model = ModelFunc(func(c Color) Color { +func nrgba64Model(c Color) Color { if _, ok := c.(NRGBA64); ok { return c } @@ -206,45 +214,41 @@ var NRGBA64Model Model = ModelFunc(func(c Color) Color { g = (g * 0xffff) / a b = (b * 0xffff) / a return NRGBA64{uint16(r), uint16(g), uint16(b), uint16(a)} -}) +} -// AlphaModel is the Model for Alpha colors. -var AlphaModel Model = ModelFunc(func(c Color) Color { +func alphaModel(c Color) Color { if _, ok := c.(Alpha); ok { return c } _, _, _, a := c.RGBA() return Alpha{uint8(a >> 8)} -}) +} -// Alpha16Model is the Model for Alpha16 colors. -var Alpha16Model Model = ModelFunc(func(c Color) Color { +func alpha16Model(c Color) Color { if _, ok := c.(Alpha16); ok { return c } _, _, _, a := c.RGBA() return Alpha16{uint16(a)} -}) +} -// GrayModel is the Model for Gray colors. -var GrayModel Model = ModelFunc(func(c Color) Color { +func grayModel(c Color) Color { if _, ok := c.(Gray); ok { return c } r, g, b, _ := c.RGBA() y := (299*r + 587*g + 114*b + 500) / 1000 return Gray{uint8(y >> 8)} -}) +} -// Gray16Model is the Model for Gray16 colors. -var Gray16Model Model = ModelFunc(func(c Color) Color { +func gray16Model(c Color) Color { if _, ok := c.(Gray16); ok { return c } r, g, b, _ := c.RGBA() y := (299*r + 587*g + 114*b + 500) / 1000 return Gray16{uint16(y)} -}) +} // Palette is a palette of colors. type Palette []Color @@ -290,13 +294,10 @@ func (p Palette) Index(c Color) int { return ret } +// Standard colors. var ( - // Black is an opaque black Color. - Black = Gray16{0} - // White is an opaque white Color. - White = Gray16{0xffff} - // Transparent is a fully transparent Color. + Black = Gray16{0} + White = Gray16{0xffff} Transparent = Alpha16{0} - // Opaque is a fully opaque Color. - Opaque = Alpha16{0xffff} + Opaque = Alpha16{0xffff} ) diff --git a/libgo/go/image/color/ycbcr.go b/libgo/go/image/color/ycbcr.go index c79816d..4c2f29e 100644 --- a/libgo/go/image/color/ycbcr.go +++ b/libgo/go/image/color/ycbcr.go @@ -4,8 +4,7 @@ package color -// RGBToYCbCr converts an RGB triple to a Y'CbCr triple. All components lie -// within the range [0, 255]. +// RGBToYCbCr converts an RGB triple to a Y'CbCr triple. func RGBToYCbCr(r, g, b uint8) (uint8, uint8, uint8) { // The JFIF specification says: // Y' = 0.2990*R + 0.5870*G + 0.1140*B @@ -36,8 +35,7 @@ func RGBToYCbCr(r, g, b uint8) (uint8, uint8, uint8) { 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]. +// YCbCrToRGB converts a Y'CbCr triple to an RGB triple. func YCbCrToRGB(y, cb, cr uint8) (uint8, uint8, uint8) { // The JFIF specification says: // R = Y' + 1.40200*(Cr-128) @@ -89,11 +87,13 @@ func (c YCbCr) RGBA() (uint32, uint32, uint32, uint32) { } // YCbCrModel is the Model for Y'CbCr colors. -var YCbCrModel Model = ModelFunc(func(c Color) Color { +var YCbCrModel Model = ModelFunc(yCbCrModel) + +func yCbCrModel(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/draw/draw.go b/libgo/go/image/draw/draw.go index 228ed6e..3b6679f 100644 --- a/libgo/go/image/draw/draw.go +++ b/libgo/go/image/draw/draw.go @@ -171,7 +171,7 @@ func drawFillOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform) { sr, sg, sb, sa := src.RGBA() // The 0x101 is here for the same reason as in drawRGBA. a := (m - sa) * 0x101 - i0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4 + i0 := dst.PixOffset(r.Min.X, r.Min.Y) i1 := i0 + r.Dx()*4 for y := r.Min.Y; y != r.Max.Y; y++ { for i := i0; i < i1; i += 4 { @@ -195,7 +195,7 @@ func drawFillSrc(dst *image.RGBA, r image.Rectangle, src *image.Uniform) { // The built-in copy function is faster than a straightforward for loop to fill the destination with // the color, but copy requires a slice source. We therefore use a for loop to fill the first row, and // then use the first row as the slice source for the remaining rows. - i0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4 + i0 := dst.PixOffset(r.Min.X, r.Min.Y) i1 := i0 + r.Dx()*4 for i := i0; i < i1; i += 4 { dst.Pix[i+0] = uint8(sr >> 8) @@ -213,8 +213,8 @@ func drawFillSrc(dst *image.RGBA, r image.Rectangle, src *image.Uniform) { func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) { dx, dy := r.Dx(), r.Dy() - d0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4 - s0 := (sp.Y-src.Rect.Min.Y)*src.Stride + (sp.X-src.Rect.Min.X)*4 + d0 := dst.PixOffset(r.Min.X, r.Min.Y) + s0 := src.PixOffset(sp.X, sp.Y) var ( ddelta, sdelta int i0, i1, idelta int @@ -261,8 +261,8 @@ func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image. func drawCopySrc(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) { n, dy := 4*r.Dx(), r.Dy() - d0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4 - s0 := (sp.Y-src.Rect.Min.Y)*src.Stride + (sp.X-src.Rect.Min.X)*4 + d0 := dst.PixOffset(r.Min.X, r.Min.Y) + s0 := src.PixOffset(sp.X, sp.Y) var ddelta, sdelta int if r.Min.Y <= sp.Y { ddelta = dst.Stride @@ -348,9 +348,6 @@ func drawNRGBASrc(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image 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 - ) x0 := (r.Min.X - dst.Rect.Min.X) * 4 x1 := (r.Max.X - dst.Rect.Min.X) * 4 y0 := r.Min.Y - dst.Rect.Min.Y @@ -359,12 +356,11 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Po 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 { - i := sx / 2 - yy = src.Y[sy*src.YStride+sx] - cb = src.Cb[sy*src.CStride+i] - cr = src.Cr[sy*src.CStride+i] - rr, gg, bb := color.YCbCrToRGB(yy, cb, cr) + yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X) + ciBase := (sy-src.Rect.Min.Y)*src.CStride - src.Rect.Min.X/2 + for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 { + ci := ciBase + sx/2 + rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci]) dpix[x+0] = rr dpix[x+1] = gg dpix[x+2] = bb @@ -374,12 +370,11 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Po 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 { - i, j := sx/2, sy/2 - yy = src.Y[sy*src.YStride+sx] - cb = src.Cb[j*src.CStride+i] - cr = src.Cr[j*src.CStride+i] - rr, gg, bb := color.YCbCrToRGB(yy, cb, cr) + yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X) + ciBase := (sy/2-src.Rect.Min.Y/2)*src.CStride - src.Rect.Min.X/2 + for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 { + ci := ciBase + sx/2 + rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci]) dpix[x+0] = rr dpix[x+1] = gg dpix[x+2] = bb @@ -390,11 +385,10 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Po // Default to 4:4:4 subsampling. 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 { - yy = src.Y[sy*src.YStride+sx] - cb = src.Cb[sy*src.CStride+sx] - cr = src.Cr[sy*src.CStride+sx] - rr, gg, bb := color.YCbCrToRGB(yy, cb, cr) + yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X) + ci := (sy-src.Rect.Min.Y)*src.CStride + (sp.X - src.Rect.Min.X) + for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 { + rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci]) dpix[x+0] = rr dpix[x+1] = gg dpix[x+2] = bb @@ -405,9 +399,9 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Po } func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform, mask *image.Alpha, mp image.Point) { - i0 := (r.Min.Y-dst.Rect.Min.Y)*dst.Stride + (r.Min.X-dst.Rect.Min.X)*4 + i0 := dst.PixOffset(r.Min.X, r.Min.Y) i1 := i0 + r.Dx()*4 - mi0 := (mp.Y-mask.Rect.Min.Y)*mask.Stride + mp.X - mask.Rect.Min.X + mi0 := mask.PixOffset(mp.X, mp.Y) sr, sg, sb, sa := src.RGBA() for y, my := r.Min.Y, mp.Y; y != r.Max.Y; y, my = y+1, my+1 { for i, mi := i0, mi0; i < i1; i, mi = i+4, mi+1 { @@ -451,7 +445,7 @@ func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Poin sx0 := sp.X + x0 - r.Min.X mx0 := mp.X + x0 - r.Min.X sx1 := sx0 + (x1 - x0) - i0 := (y0-dst.Rect.Min.Y)*dst.Stride + (x0-dst.Rect.Min.X)*4 + i0 := dst.PixOffset(x0, y0) di := dx * 4 for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy { for i, sx, mx := i0, sx0, mx0; sx != sx1; i, sx, mx = i+di, sx+dx, mx+dx { diff --git a/libgo/go/image/geom.go b/libgo/go/image/geom.go index 667aee6..e123483 100644 --- a/libgo/go/image/geom.go +++ b/libgo/go/image/geom.go @@ -112,7 +112,7 @@ func (r Rectangle) Add(p Point) Rectangle { } } -// Add returns the rectangle r translated by -p. +// Sub returns the rectangle r translated by -p. func (r Rectangle) Sub(p Point) Rectangle { return Rectangle{ Point{r.Min.X - p.X, r.Min.Y - p.Y}, diff --git a/libgo/go/image/image.go b/libgo/go/image/image.go index a0dd930..9dd676a 100644 --- a/libgo/go/image/image.go +++ b/libgo/go/image/image.go @@ -61,15 +61,21 @@ func (p *RGBA) At(x, y int) color.Color { if !(Point{x, y}.In(p.Rect)) { return color.RGBA{} } - i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4 + i := p.PixOffset(x, y) return color.RGBA{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]} } +// PixOffset returns the index of the first element of Pix that corresponds to +// the pixel at (x, y). +func (p *RGBA) PixOffset(x, y int) int { + return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4 +} + func (p *RGBA) Set(x, y int, c color.Color) { if !(Point{x, y}.In(p.Rect)) { return } - i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4 + i := p.PixOffset(x, y) c1 := color.RGBAModel.Convert(c).(color.RGBA) p.Pix[i+0] = c1.R p.Pix[i+1] = c1.G @@ -81,7 +87,7 @@ func (p *RGBA) SetRGBA(x, y int, c color.RGBA) { if !(Point{x, y}.In(p.Rect)) { return } - i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4 + i := p.PixOffset(x, y) p.Pix[i+0] = c.R p.Pix[i+1] = c.G p.Pix[i+2] = c.B @@ -98,7 +104,7 @@ func (p *RGBA) SubImage(r Rectangle) Image { if r.Empty() { return &RGBA{} } - i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*4 + i := p.PixOffset(r.Min.X, r.Min.Y) return &RGBA{ Pix: p.Pix[i:], Stride: p.Stride, @@ -124,7 +130,7 @@ func (p *RGBA) Opaque() bool { return true } -// NewRGBA returns a new RGBA with the given width and height. +// NewRGBA returns a new RGBA with the given bounds. func NewRGBA(r Rectangle) *RGBA { w, h := r.Dx(), r.Dy() buf := make([]uint8, 4*w*h) @@ -150,7 +156,7 @@ func (p *RGBA64) At(x, y int) color.Color { if !(Point{x, y}.In(p.Rect)) { return color.RGBA64{} } - i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8 + i := p.PixOffset(x, y) return color.RGBA64{ uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1]), uint16(p.Pix[i+2])<<8 | uint16(p.Pix[i+3]), @@ -159,11 +165,17 @@ func (p *RGBA64) At(x, y int) color.Color { } } +// PixOffset returns the index of the first element of Pix that corresponds to +// the pixel at (x, y). +func (p *RGBA64) PixOffset(x, y int) int { + return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8 +} + func (p *RGBA64) Set(x, y int, c color.Color) { if !(Point{x, y}.In(p.Rect)) { return } - i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8 + i := p.PixOffset(x, y) c1 := color.RGBA64Model.Convert(c).(color.RGBA64) p.Pix[i+0] = uint8(c1.R >> 8) p.Pix[i+1] = uint8(c1.R) @@ -179,7 +191,7 @@ func (p *RGBA64) SetRGBA64(x, y int, c color.RGBA64) { if !(Point{x, y}.In(p.Rect)) { return } - i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8 + i := p.PixOffset(x, y) p.Pix[i+0] = uint8(c.R >> 8) p.Pix[i+1] = uint8(c.R) p.Pix[i+2] = uint8(c.G >> 8) @@ -200,7 +212,7 @@ func (p *RGBA64) SubImage(r Rectangle) Image { if r.Empty() { return &RGBA64{} } - i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*8 + i := p.PixOffset(r.Min.X, r.Min.Y) return &RGBA64{ Pix: p.Pix[i:], Stride: p.Stride, @@ -226,7 +238,7 @@ func (p *RGBA64) Opaque() bool { return true } -// NewRGBA64 returns a new RGBA64 with the given width and height. +// NewRGBA64 returns a new RGBA64 with the given bounds. func NewRGBA64(r Rectangle) *RGBA64 { w, h := r.Dx(), r.Dy() pix := make([]uint8, 8*w*h) @@ -252,15 +264,21 @@ func (p *NRGBA) At(x, y int) color.Color { if !(Point{x, y}.In(p.Rect)) { return color.NRGBA{} } - i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4 + i := p.PixOffset(x, y) return color.NRGBA{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]} } +// PixOffset returns the index of the first element of Pix that corresponds to +// the pixel at (x, y). +func (p *NRGBA) PixOffset(x, y int) int { + return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4 +} + func (p *NRGBA) Set(x, y int, c color.Color) { if !(Point{x, y}.In(p.Rect)) { return } - i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4 + i := p.PixOffset(x, y) c1 := color.NRGBAModel.Convert(c).(color.NRGBA) p.Pix[i+0] = c1.R p.Pix[i+1] = c1.G @@ -272,7 +290,7 @@ func (p *NRGBA) SetNRGBA(x, y int, c color.NRGBA) { if !(Point{x, y}.In(p.Rect)) { return } - i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4 + i := p.PixOffset(x, y) p.Pix[i+0] = c.R p.Pix[i+1] = c.G p.Pix[i+2] = c.B @@ -289,7 +307,7 @@ func (p *NRGBA) SubImage(r Rectangle) Image { if r.Empty() { return &NRGBA{} } - i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*4 + i := p.PixOffset(r.Min.X, r.Min.Y) return &NRGBA{ Pix: p.Pix[i:], Stride: p.Stride, @@ -315,7 +333,7 @@ func (p *NRGBA) Opaque() bool { return true } -// NewNRGBA returns a new NRGBA with the given width and height. +// NewNRGBA returns a new NRGBA with the given bounds. func NewNRGBA(r Rectangle) *NRGBA { w, h := r.Dx(), r.Dy() pix := make([]uint8, 4*w*h) @@ -341,7 +359,7 @@ func (p *NRGBA64) At(x, y int) color.Color { if !(Point{x, y}.In(p.Rect)) { return color.NRGBA64{} } - i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8 + i := p.PixOffset(x, y) return color.NRGBA64{ uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1]), uint16(p.Pix[i+2])<<8 | uint16(p.Pix[i+3]), @@ -350,11 +368,17 @@ func (p *NRGBA64) At(x, y int) color.Color { } } +// PixOffset returns the index of the first element of Pix that corresponds to +// the pixel at (x, y). +func (p *NRGBA64) PixOffset(x, y int) int { + return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8 +} + func (p *NRGBA64) Set(x, y int, c color.Color) { if !(Point{x, y}.In(p.Rect)) { return } - i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8 + i := p.PixOffset(x, y) c1 := color.NRGBA64Model.Convert(c).(color.NRGBA64) p.Pix[i+0] = uint8(c1.R >> 8) p.Pix[i+1] = uint8(c1.R) @@ -370,7 +394,7 @@ func (p *NRGBA64) SetNRGBA64(x, y int, c color.NRGBA64) { if !(Point{x, y}.In(p.Rect)) { return } - i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*8 + i := p.PixOffset(x, y) p.Pix[i+0] = uint8(c.R >> 8) p.Pix[i+1] = uint8(c.R) p.Pix[i+2] = uint8(c.G >> 8) @@ -391,7 +415,7 @@ func (p *NRGBA64) SubImage(r Rectangle) Image { if r.Empty() { return &NRGBA64{} } - i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*8 + i := p.PixOffset(r.Min.X, r.Min.Y) return &NRGBA64{ Pix: p.Pix[i:], Stride: p.Stride, @@ -417,7 +441,7 @@ func (p *NRGBA64) Opaque() bool { return true } -// NewNRGBA64 returns a new NRGBA64 with the given width and height. +// NewNRGBA64 returns a new NRGBA64 with the given bounds. func NewNRGBA64(r Rectangle) *NRGBA64 { w, h := r.Dx(), r.Dy() pix := make([]uint8, 8*w*h) @@ -443,15 +467,21 @@ func (p *Alpha) At(x, y int) color.Color { if !(Point{x, y}.In(p.Rect)) { return color.Alpha{} } - i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X) + i := p.PixOffset(x, y) return color.Alpha{p.Pix[i]} } +// PixOffset returns the index of the first element of Pix that corresponds to +// the pixel at (x, y). +func (p *Alpha) PixOffset(x, y int) int { + return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*1 +} + func (p *Alpha) Set(x, y int, c color.Color) { if !(Point{x, y}.In(p.Rect)) { return } - i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X) + i := p.PixOffset(x, y) p.Pix[i] = color.AlphaModel.Convert(c).(color.Alpha).A } @@ -459,7 +489,7 @@ func (p *Alpha) SetAlpha(x, y int, c color.Alpha) { if !(Point{x, y}.In(p.Rect)) { return } - i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X) + i := p.PixOffset(x, y) p.Pix[i] = c.A } @@ -473,7 +503,7 @@ func (p *Alpha) SubImage(r Rectangle) Image { if r.Empty() { return &Alpha{} } - i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*1 + i := p.PixOffset(r.Min.X, r.Min.Y) return &Alpha{ Pix: p.Pix[i:], Stride: p.Stride, @@ -499,7 +529,7 @@ func (p *Alpha) Opaque() bool { return true } -// NewAlpha returns a new Alpha with the given width and height. +// NewAlpha returns a new Alpha with the given bounds. func NewAlpha(r Rectangle) *Alpha { w, h := r.Dx(), r.Dy() pix := make([]uint8, 1*w*h) @@ -525,15 +555,21 @@ func (p *Alpha16) At(x, y int) color.Color { if !(Point{x, y}.In(p.Rect)) { return color.Alpha16{} } - i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2 + i := p.PixOffset(x, y) return color.Alpha16{uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1])} } +// PixOffset returns the index of the first element of Pix that corresponds to +// the pixel at (x, y). +func (p *Alpha16) PixOffset(x, y int) int { + return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2 +} + func (p *Alpha16) Set(x, y int, c color.Color) { if !(Point{x, y}.In(p.Rect)) { return } - i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2 + i := p.PixOffset(x, y) c1 := color.Alpha16Model.Convert(c).(color.Alpha16) p.Pix[i+0] = uint8(c1.A >> 8) p.Pix[i+1] = uint8(c1.A) @@ -543,7 +579,7 @@ func (p *Alpha16) SetAlpha16(x, y int, c color.Alpha16) { if !(Point{x, y}.In(p.Rect)) { return } - i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2 + i := p.PixOffset(x, y) p.Pix[i+0] = uint8(c.A >> 8) p.Pix[i+1] = uint8(c.A) } @@ -558,7 +594,7 @@ func (p *Alpha16) SubImage(r Rectangle) Image { if r.Empty() { return &Alpha16{} } - i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*2 + i := p.PixOffset(r.Min.X, r.Min.Y) return &Alpha16{ Pix: p.Pix[i:], Stride: p.Stride, @@ -584,7 +620,7 @@ func (p *Alpha16) Opaque() bool { return true } -// NewAlpha16 returns a new Alpha16 with the given width and height. +// NewAlpha16 returns a new Alpha16 with the given bounds. func NewAlpha16(r Rectangle) *Alpha16 { w, h := r.Dx(), r.Dy() pix := make([]uint8, 2*w*h) @@ -610,15 +646,21 @@ func (p *Gray) At(x, y int) color.Color { if !(Point{x, y}.In(p.Rect)) { return color.Gray{} } - i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X) + i := p.PixOffset(x, y) return color.Gray{p.Pix[i]} } +// PixOffset returns the index of the first element of Pix that corresponds to +// the pixel at (x, y). +func (p *Gray) PixOffset(x, y int) int { + return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*1 +} + func (p *Gray) Set(x, y int, c color.Color) { if !(Point{x, y}.In(p.Rect)) { return } - i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X) + i := p.PixOffset(x, y) p.Pix[i] = color.GrayModel.Convert(c).(color.Gray).Y } @@ -626,7 +668,7 @@ func (p *Gray) SetGray(x, y int, c color.Gray) { if !(Point{x, y}.In(p.Rect)) { return } - i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X) + i := p.PixOffset(x, y) p.Pix[i] = c.Y } @@ -640,7 +682,7 @@ func (p *Gray) SubImage(r Rectangle) Image { if r.Empty() { return &Gray{} } - i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*1 + i := p.PixOffset(r.Min.X, r.Min.Y) return &Gray{ Pix: p.Pix[i:], Stride: p.Stride, @@ -653,7 +695,7 @@ func (p *Gray) Opaque() bool { return true } -// NewGray returns a new Gray with the given width and height. +// NewGray returns a new Gray with the given bounds. func NewGray(r Rectangle) *Gray { w, h := r.Dx(), r.Dy() pix := make([]uint8, 1*w*h) @@ -679,15 +721,21 @@ func (p *Gray16) At(x, y int) color.Color { if !(Point{x, y}.In(p.Rect)) { return color.Gray16{} } - i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2 + i := p.PixOffset(x, y) return color.Gray16{uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1])} } +// PixOffset returns the index of the first element of Pix that corresponds to +// the pixel at (x, y). +func (p *Gray16) PixOffset(x, y int) int { + return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2 +} + func (p *Gray16) Set(x, y int, c color.Color) { if !(Point{x, y}.In(p.Rect)) { return } - i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2 + i := p.PixOffset(x, y) c1 := color.Gray16Model.Convert(c).(color.Gray16) p.Pix[i+0] = uint8(c1.Y >> 8) p.Pix[i+1] = uint8(c1.Y) @@ -697,7 +745,7 @@ func (p *Gray16) SetGray16(x, y int, c color.Gray16) { if !(Point{x, y}.In(p.Rect)) { return } - i := (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*2 + i := p.PixOffset(x, y) p.Pix[i+0] = uint8(c.Y >> 8) p.Pix[i+1] = uint8(c.Y) } @@ -712,7 +760,7 @@ func (p *Gray16) SubImage(r Rectangle) Image { if r.Empty() { return &Gray16{} } - i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*2 + i := p.PixOffset(r.Min.X, r.Min.Y) return &Gray16{ Pix: p.Pix[i:], Stride: p.Stride, @@ -725,7 +773,7 @@ func (p *Gray16) Opaque() bool { return true } -// NewGray16 returns a new Gray16 with the given width and height. +// NewGray16 returns a new Gray16 with the given bounds. func NewGray16(r Rectangle) *Gray16 { w, h := r.Dx(), r.Dy() pix := make([]uint8, 2*w*h) @@ -756,15 +804,21 @@ func (p *Paletted) At(x, y int) color.Color { if !(Point{x, y}.In(p.Rect)) { return p.Palette[0] } - i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X) + i := p.PixOffset(x, y) return p.Palette[p.Pix[i]] } +// PixOffset returns the index of the first element of Pix that corresponds to +// the pixel at (x, y). +func (p *Paletted) PixOffset(x, y int) int { + return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*1 +} + func (p *Paletted) Set(x, y int, c color.Color) { if !(Point{x, y}.In(p.Rect)) { return } - i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X) + i := p.PixOffset(x, y) p.Pix[i] = uint8(p.Palette.Index(c)) } @@ -772,7 +826,7 @@ func (p *Paletted) ColorIndexAt(x, y int) uint8 { if !(Point{x, y}.In(p.Rect)) { return 0 } - i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X) + i := p.PixOffset(x, y) return p.Pix[i] } @@ -780,7 +834,7 @@ func (p *Paletted) SetColorIndex(x, y int, index uint8) { if !(Point{x, y}.In(p.Rect)) { return } - i := (y-p.Rect.Min.Y)*p.Stride + (x - p.Rect.Min.X) + i := p.PixOffset(x, y) p.Pix[i] = index } @@ -796,7 +850,7 @@ func (p *Paletted) SubImage(r Rectangle) Image { Palette: p.Palette, } } - i := (r.Min.Y-p.Rect.Min.Y)*p.Stride + (r.Min.X-p.Rect.Min.X)*1 + i := p.PixOffset(r.Min.X, r.Min.Y) return &Paletted{ Pix: p.Pix[i:], Stride: p.Stride, diff --git a/libgo/go/image/jpeg/reader.go b/libgo/go/image/jpeg/reader.go index ed1a962..2e412ad 100644 --- a/libgo/go/image/jpeg/reader.go +++ b/libgo/go/image/jpeg/reader.go @@ -203,8 +203,7 @@ func (d *decoder) makeImg(h0, v0, mxx, myy int) { return } var subsampleRatio image.YCbCrSubsampleRatio - n := h0 * v0 - switch n { + switch h0 * v0 { case 1: subsampleRatio = image.YCbCrSubsampleRatio444 case 2: @@ -214,16 +213,8 @@ func (d *decoder) makeImg(h0, v0, mxx, myy int) { default: panic("unreachable") } - b := make([]byte, mxx*myy*(1*8*8*n+2*8*8)) - 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)], - SubsampleRatio: subsampleRatio, - YStride: mxx * 8 * h0, - CStride: mxx * 8, - Rect: image.Rect(0, 0, d.width, d.height), - } + m := image.NewYCbCr(image.Rect(0, 0, 8*h0*mxx, 8*v0*myy), subsampleRatio) + d.img3 = m.SubImage(image.Rect(0, 0, d.width, d.height)).(*image.YCbCr) } // Specified in section B.2.3. diff --git a/libgo/go/image/tiff/reader.go b/libgo/go/image/tiff/reader.go index 00a51db..dc5a87a 100644 --- a/libgo/go/image/tiff/reader.go +++ b/libgo/go/image/tiff/reader.go @@ -223,8 +223,8 @@ func (d *decoder) decode(dst image.Image, ymin, ymax int) error { } case mRGB: img := dst.(*image.RGBA) - min := (ymin-img.Rect.Min.Y)*img.Stride - img.Rect.Min.X*4 - max := (ymax-img.Rect.Min.Y)*img.Stride - img.Rect.Min.X*4 + min := img.PixOffset(0, ymin) + max := img.PixOffset(0, ymax) var off int for i := min; i < max; i += 4 { img.Pix[i+0] = d.buf[off+0] @@ -235,16 +235,16 @@ func (d *decoder) decode(dst image.Image, ymin, ymax int) error { } case mNRGBA: img := dst.(*image.NRGBA) - min := (ymin-img.Rect.Min.Y)*img.Stride - img.Rect.Min.X*4 - max := (ymax-img.Rect.Min.Y)*img.Stride - img.Rect.Min.X*4 + min := img.PixOffset(0, ymin) + max := img.PixOffset(0, ymax) if len(d.buf) != max-min { return FormatError("short data strip") } copy(img.Pix[min:max], d.buf) case mRGBA: img := dst.(*image.RGBA) - min := (ymin-img.Rect.Min.Y)*img.Stride - img.Rect.Min.X*4 - max := (ymax-img.Rect.Min.Y)*img.Stride - img.Rect.Min.X*4 + min := img.PixOffset(0, ymin) + max := img.PixOffset(0, ymax) if len(d.buf) != max-min { return FormatError("short data strip") } diff --git a/libgo/go/image/ycbcr.go b/libgo/go/image/ycbcr.go index 81f3c9f..c1a0b66 100644 --- a/libgo/go/image/ycbcr.go +++ b/libgo/go/image/ycbcr.go @@ -17,6 +17,18 @@ const ( YCbCrSubsampleRatio420 ) +func (s YCbCrSubsampleRatio) String() string { + switch s { + case YCbCrSubsampleRatio444: + return "YCbCrSubsampleRatio444" + case YCbCrSubsampleRatio422: + return "YCbCrSubsampleRatio422" + case YCbCrSubsampleRatio420: + return "YCbCrSubsampleRatio420" + } + return "YCbCrSubsampleRatioUnknown" +} + // 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. @@ -28,9 +40,7 @@ const ( // 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 + Y, Cb, Cr []uint8 YStride int CStride int SubsampleRatio YCbCrSubsampleRatio @@ -49,39 +59,86 @@ func (p *YCbCr) At(x, y int) color.Color { if !(Point{x, y}.In(p.Rect)) { return color.YCbCr{} } + yi := p.YOffset(x, y) + ci := p.COffset(x, y) + return color.YCbCr{ + p.Y[yi], + p.Cb[ci], + p.Cr[ci], + } +} + +// YOffset returns the index of the first element of Y that corresponds to +// the pixel at (x, y). +func (p *YCbCr) YOffset(x, y int) int { + return (y-p.Rect.Min.Y)*p.YStride + (x - p.Rect.Min.X) +} + +// COffset returns the index of the first element of Cb or Cr that corresponds +// to the pixel at (x, y). +func (p *YCbCr) COffset(x, y int) int { 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], - } + return (y-p.Rect.Min.Y)*p.CStride + (x/2 - p.Rect.Min.X/2) 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], - } + return (y/2-p.Rect.Min.Y/2)*p.CStride + (x/2 - p.Rect.Min.X/2) } // 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], - } + return (y-p.Rect.Min.Y)*p.CStride + (x - p.Rect.Min.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 + r = r.Intersect(p.Rect) + // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside + // either r1 or r2 if the intersection is empty. Without explicitly checking for + // this, the Pix[i:] expression below can panic. + if r.Empty() { + return &YCbCr{ + SubsampleRatio: p.SubsampleRatio, + } + } + yi := p.YOffset(r.Min.X, r.Min.Y) + ci := p.COffset(r.Min.X, r.Min.Y) + return &YCbCr{ + Y: p.Y[yi:], + Cb: p.Cb[ci:], + Cr: p.Cr[ci:], + SubsampleRatio: p.SubsampleRatio, + YStride: p.YStride, + CStride: p.CStride, + Rect: r, + } } func (p *YCbCr) Opaque() bool { return true } + +// NewYCbCr returns a new YCbCr with the given bounds and subsample ratio. +func NewYCbCr(r Rectangle, subsampleRatio YCbCrSubsampleRatio) *YCbCr { + w, h, cw, ch := r.Dx(), r.Dy(), 0, 0 + switch subsampleRatio { + case YCbCrSubsampleRatio422: + cw = (r.Max.X+1)/2 - r.Min.X/2 + ch = h + case YCbCrSubsampleRatio420: + cw = (r.Max.X+1)/2 - r.Min.X/2 + ch = (r.Max.Y+1)/2 - r.Min.Y/2 + default: + // Default to 4:4:4 subsampling. + cw = w + ch = h + } + b := make([]byte, w*h+2*cw*ch) + return &YCbCr{ + Y: b[:w*h], + Cb: b[w*h+0*cw*ch : w*h+1*cw*ch], + Cr: b[w*h+1*cw*ch : w*h+2*cw*ch], + SubsampleRatio: subsampleRatio, + YStride: w, + CStride: cw, + Rect: r, + } +} diff --git a/libgo/go/image/ycbcr_test.go b/libgo/go/image/ycbcr_test.go new file mode 100644 index 0000000..eb8b195 --- /dev/null +++ b/libgo/go/image/ycbcr_test.go @@ -0,0 +1,104 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package image_test + +import ( + . "image" + "image/color" + "testing" +) + +func TestYCbCr(t *testing.T) { + rects := []Rectangle{ + Rect(0, 0, 16, 16), + Rect(1, 0, 16, 16), + Rect(0, 1, 16, 16), + Rect(1, 1, 16, 16), + Rect(1, 1, 15, 16), + Rect(1, 1, 16, 15), + Rect(1, 1, 15, 15), + Rect(2, 3, 14, 15), + Rect(7, 0, 7, 16), + Rect(0, 8, 16, 8), + Rect(0, 0, 10, 11), + Rect(5, 6, 16, 16), + Rect(7, 7, 8, 8), + Rect(7, 8, 8, 9), + Rect(8, 7, 9, 8), + Rect(8, 8, 9, 9), + Rect(7, 7, 17, 17), + Rect(8, 8, 17, 17), + Rect(9, 9, 17, 17), + Rect(10, 10, 17, 17), + } + subsampleRatios := []YCbCrSubsampleRatio{ + YCbCrSubsampleRatio444, + YCbCrSubsampleRatio422, + YCbCrSubsampleRatio420, + } + deltas := []Point{ + Pt(0, 0), + Pt(1000, 1001), + Pt(5001, -400), + Pt(-701, -801), + } + for _, r := range rects { + for _, subsampleRatio := range subsampleRatios { + for _, delta := range deltas { + testYCbCr(t, r, subsampleRatio, delta) + } + } + } +} + +func testYCbCr(t *testing.T, r Rectangle, subsampleRatio YCbCrSubsampleRatio, delta Point) { + // Create a YCbCr image m, whose bounds are r translated by (delta.X, delta.Y). + r1 := r.Add(delta) + m := NewYCbCr(r1, subsampleRatio) + + // Test that the image buffer is reasonably small even if (delta.X, delta.Y) is far from the origin. + if len(m.Y) > 100*100 { + t.Errorf("r=%v, subsampleRatio=%v, delta=%v: image buffer is too large", + r, subsampleRatio, delta) + return + } + + // Initialize m's pixels. For 422 and 420 subsampling, some of the Cb and Cr elements + // will be set multiple times. That's OK. We just want to avoid a uniform image. + for y := r1.Min.Y; y < r1.Max.Y; y++ { + for x := r1.Min.X; x < r1.Max.X; x++ { + yi := m.YOffset(x, y) + ci := m.COffset(x, y) + m.Y[yi] = uint8(16*y + x) + m.Cb[ci] = uint8(y + 16*x) + m.Cr[ci] = uint8(y + 16*x) + } + } + + // Make various sub-images of m. + for y0 := delta.Y + 3; y0 < delta.Y+7; y0++ { + for y1 := delta.Y + 8; y1 < delta.Y+13; y1++ { + for x0 := delta.X + 3; x0 < delta.X+7; x0++ { + for x1 := delta.X + 8; x1 < delta.X+13; x1++ { + subRect := Rect(x0, y0, x1, y1) + sub := m.SubImage(subRect).(*YCbCr) + + // For each point in the sub-image's bounds, check that m.At(x, y) equals sub.At(x, y). + for y := sub.Rect.Min.Y; y < sub.Rect.Max.Y; y++ { + for x := sub.Rect.Min.X; x < sub.Rect.Max.X; x++ { + color0 := m.At(x, y).(color.YCbCr) + color1 := sub.At(x, y).(color.YCbCr) + if color0 != color1 { + t.Errorf("r=%v, subsampleRatio=%v, delta=%v, x=%d, y=%d, color0=%v, color1=%v", + r, subsampleRatio, delta, x, y, color0, color1) + return + } + } + } + } + } + } + } +} diff --git a/libgo/go/io/ioutil/ioutil.go b/libgo/go/io/ioutil/ioutil.go index be7fa5f..65f4b3a 100644 --- a/libgo/go/io/ioutil/ioutil.go +++ b/libgo/go/io/ioutil/ioutil.go @@ -50,7 +50,7 @@ func ReadFile(filename string) ([]byte, error) { // WriteFile writes data to a file named by filename. // If the file does not exist, WriteFile creates it with permissions perm; // otherwise WriteFile truncates it before writing. -func WriteFile(filename string, data []byte, perm uint32) error { +func WriteFile(filename string, data []byte, perm os.FileMode) error { f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm) if err != nil { return err diff --git a/libgo/go/log/syslog/syslog_test.go b/libgo/go/log/syslog/syslog_test.go index 5c0b3e0..b9793e9 100644 --- a/libgo/go/log/syslog/syslog_test.go +++ b/libgo/go/log/syslog/syslog_test.go @@ -8,6 +8,7 @@ import ( "log" "net" "testing" + "time" ) var serverAddr string @@ -31,7 +32,7 @@ func startServer(done chan<- string) { log.Fatalf("net.ListenPacket failed udp :0 %v", e) } serverAddr = c.LocalAddr().String() - c.SetReadTimeout(100e6) // 100ms + c.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) go runSyslog(c, done) } diff --git a/libgo/go/math/rand/rand.go b/libgo/go/math/rand/rand.go index 459aed1..8955219 100644 --- a/libgo/go/math/rand/rand.go +++ b/libgo/go/math/rand/rand.go @@ -107,7 +107,9 @@ func (r *Rand) Perm(n int) []int { var globalRand = New(&lockedSource{src: NewSource(1)}) -// Seed uses the provided seed value to initialize the generator to a deterministic state. +// Seed uses the provided seed value to initialize the generator to a +// deterministic state. If Seed is not called, the generator behaves as +// if seeded by Seed(1). func Seed(seed int64) { globalRand.Seed(seed) } // Int63 returns a non-negative pseudo-random 63-bit integer as an int64. diff --git a/libgo/go/math/rand/rand_test.go b/libgo/go/math/rand/rand_test.go index 76215a9..0ba8f98 100644 --- a/libgo/go/math/rand/rand_test.go +++ b/libgo/go/math/rand/rand_test.go @@ -131,8 +131,14 @@ func TestStandardNormalValues(t *testing.T) { } func TestNonStandardNormalValues(t *testing.T) { - for sd := 0.5; sd < 1000; sd *= 2 { - for m := 0.5; m < 1000; m *= 2 { + sdmax := 1000.0 + mmax := 1000.0 + if testing.Short() { + sdmax = 5 + mmax = 5 + } + for sd := 0.5; sd < sdmax; sd *= 2 { + for m := 0.5; m < mmax; m *= 2 { for _, seed := range testSeeds { testNormalDistribution(t, numTestSamples, m, sd, seed) } diff --git a/libgo/go/mime/mediatype.go b/libgo/go/mime/mediatype.go index 2bf7978..41844c2 100644 --- a/libgo/go/mime/mediatype.go +++ b/libgo/go/mime/mediatype.go @@ -12,17 +12,22 @@ import ( "unicode" ) -// FormatMediaType serializes type t, subtype sub and the paramaters -// param as a media type conform RFC 2045 and RFC 2616. -// The type, subtype, and parameter names are written in lower-case. +// FormatMediaType serializes mediatype t and the parameters +// param as a media type conforming to RFC 2045 and RFC 2616. +// The type and parameter names are written in lower-case. // When any of the arguments result in a standard violation then // FormatMediaType returns the empty string. -func FormatMediaType(t, sub string, param map[string]string) string { - if !(IsToken(t) && IsToken(sub)) { +func FormatMediaType(t string, param map[string]string) string { + slash := strings.Index(t, "/") + if slash == -1 { + return "" + } + major, sub := t[:slash], t[slash+1:] + if !IsToken(major) || !IsToken(sub) { return "" } var b bytes.Buffer - b.WriteString(strings.ToLower(t)) + b.WriteString(strings.ToLower(major)) b.WriteByte('/') b.WriteString(strings.ToLower(sub)) diff --git a/libgo/go/mime/mediatype_test.go b/libgo/go/mime/mediatype_test.go index c06f167..64ab291 100644 --- a/libgo/go/mime/mediatype_test.go +++ b/libgo/go/mime/mediatype_test.go @@ -253,3 +253,24 @@ func TestParseMediaTypeBogus(t *testing.T) { t.Errorf("expected invalid media parameter; got error %q", err) } } + +type formatTest struct { + typ string + params map[string]string + want string +} + +var formatTests = []formatTest{ + {"noslash", nil, ""}, + {"foo/BAR", nil, "foo/bar"}, + {"foo/BAR", map[string]string{"X": "Y"}, "foo/bar; x=Y"}, +} + +func TestFormatMediaType(t *testing.T) { + for i, tt := range formatTests { + got := FormatMediaType(tt.typ, tt.params) + if got != tt.want { + t.Errorf("%d. FormatMediaType(%q, %v) = %q; want %q", i, tt.typ, tt.params, got, tt.want) + } + } +} diff --git a/libgo/go/mime/type.go b/libgo/go/mime/type.go index e3d968f..00cff26 100644 --- a/libgo/go/mime/type.go +++ b/libgo/go/mime/type.go @@ -62,21 +62,14 @@ func AddExtensionType(ext, typ string) error { } func setExtensionType(extension, mimeType string) error { - full, param, err := ParseMediaType(mimeType) + _, param, err := ParseMediaType(mimeType) if err != nil { return err } - if split := strings.Index(full, "/"); split < 0 { - return fmt.Errorf(`mime: malformed MIME type "%s"`, mimeType) - } else { - main := full[:split] - sub := full[split+1:] - if main == "text" && param["charset"] == "" { - param["charset"] = "utf-8" - } - mimeType = FormatMediaType(main, sub, param) + if strings.HasPrefix(mimeType, "text/") && param["charset"] == "" { + param["charset"] = "utf-8" + mimeType = FormatMediaType(mimeType, param) } - mimeLock.Lock() mimeTypes[extension] = mimeType mimeLock.Unlock() diff --git a/libgo/go/net/dnsclient_unix.go b/libgo/go/net/dnsclient_unix.go index 07e72cc..18c3936 100644 --- a/libgo/go/net/dnsclient_unix.go +++ b/libgo/go/net/dnsclient_unix.go @@ -45,7 +45,11 @@ func exchange(cfg *dnsConfig, c Conn, name string, qtype uint16) (*dnsMsg, error return nil, err } - c.SetReadTimeout(int64(cfg.timeout) * 1e9) // nanoseconds + if cfg.timeout == 0 { + c.SetReadDeadline(time.Time{}) + } else { + c.SetReadDeadline(time.Now().Add(time.Duration(cfg.timeout) * time.Second)) + } buf := make([]byte, 2000) // More than enough. n, err = c.Read(buf) diff --git a/libgo/go/net/doc.go b/libgo/go/net/doc.go new file mode 100644 index 0000000..3a44e52 --- /dev/null +++ b/libgo/go/net/doc.go @@ -0,0 +1,59 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +// LookupHost looks up the given host using the local resolver. +// It returns an array of that host's addresses. +func LookupHost(host string) (addrs []string, err error) { + return lookupHost(host) +} + +// LookupIP looks up host using the local resolver. +// It returns an array of that host's IPv4 and IPv6 addresses. +func LookupIP(host string) (addrs []IP, err error) { + return lookupIP(host) +} + +// LookupPort looks up the port for the given network and service. +func LookupPort(network, service string) (port int, err error) { + return lookupPort(network, service) +} + +// LookupCNAME returns the canonical DNS host for the given name. +// Callers that do not care about the canonical name can call +// LookupHost or LookupIP directly; both take care of resolving +// the canonical name as part of the lookup. +func LookupCNAME(name string) (cname string, err error) { + return lookupCNAME(name) +} + +// LookupSRV tries to resolve an SRV query of the given service, +// protocol, and domain name. The proto is "tcp" or "udp". +// The returned records are sorted by priority and randomized +// by weight within a priority. +// +// LookupSRV constructs the DNS name to look up following RFC 2782. +// That is, it looks up _service._proto.name. To accommodate services +// publishing SRV records under non-standard names, if both service +// and proto are empty strings, LookupSRV looks up name directly. +func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) { + return lookupSRV(service, proto, name) +} + +// LookupMX returns the DNS MX records for the given domain name sorted by preference. +func LookupMX(name string) (mx []*MX, err error) { + return lookupMX(name) +} + +// LookupTXT returns the DNS TXT records for the given domain name. +func LookupTXT(name string) (txt []string, err error) { + return lookupTXT(name) +} + +// LookupAddr performs a reverse lookup for the given address, returning a list +// of names mapping to that address. +func LookupAddr(addr string) (name []string, err error) { + return lookupAddr(addr) +} diff --git a/libgo/go/net/fd.go b/libgo/go/net/fd.go index 3dec9f4..7ecd135 100644 --- a/libgo/go/net/fd.go +++ b/libgo/go/net/fd.go @@ -24,7 +24,7 @@ type netFD struct { // immutable until Close sysfd int family int - proto int + sotype int sysfile *os.File cr chan bool cw chan bool @@ -33,12 +33,10 @@ type netFD struct { raddr Addr // owned by client - rdeadline_delta int64 - rdeadline int64 - rio sync.Mutex - wdeadline_delta int64 - wdeadline int64 - wio sync.Mutex + rdeadline int64 + rio sync.Mutex + wdeadline int64 + wio sync.Mutex // owned by fd wait server ncr, ncw int @@ -276,7 +274,7 @@ func startServer() { pollserver = p } -func newFD(fd, family, proto int, net string) (f *netFD, err error) { +func newFD(fd, family, sotype int, net string) (f *netFD, err error) { onceStartServer.Do(startServer) if e := syscall.SetNonblock(fd, true); e != nil { return nil, e @@ -284,7 +282,7 @@ func newFD(fd, family, proto int, net string) (f *netFD, err error) { f = &netFD{ sysfd: fd, family: family, - proto: proto, + sotype: sotype, net: net, } f.cr = make(chan bool, 1) @@ -388,11 +386,6 @@ func (fd *netFD) Read(p []byte) (n int, err error) { if fd.sysfile == nil { return 0, os.EINVAL } - if fd.rdeadline_delta > 0 { - fd.rdeadline = pollserver.Now() + fd.rdeadline_delta - } else { - fd.rdeadline = 0 - } for { n, err = syscall.Read(fd.sysfile.Fd(), p) if err == syscall.EAGAIN { @@ -404,7 +397,7 @@ func (fd *netFD) Read(p []byte) (n int, err error) { } if err != nil { n = 0 - } else if n == 0 && err == nil && fd.proto != syscall.SOCK_DGRAM { + } else if n == 0 && err == nil && fd.sotype != syscall.SOCK_DGRAM { err = io.EOF } break @@ -423,11 +416,6 @@ func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err error) { defer fd.rio.Unlock() fd.incref() defer fd.decref() - if fd.rdeadline_delta > 0 { - fd.rdeadline = pollserver.Now() + fd.rdeadline_delta - } else { - fd.rdeadline = 0 - } for { n, sa, err = syscall.Recvfrom(fd.sysfd, p, 0) if err == syscall.EAGAIN { @@ -456,11 +444,6 @@ func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.S defer fd.rio.Unlock() fd.incref() defer fd.decref() - if fd.rdeadline_delta > 0 { - fd.rdeadline = pollserver.Now() + fd.rdeadline_delta - } else { - fd.rdeadline = 0 - } for { n, oobn, flags, sa, err = syscall.Recvmsg(fd.sysfd, p, oob, 0) if err == syscall.EAGAIN { @@ -493,11 +476,6 @@ func (fd *netFD) Write(p []byte) (n int, err error) { if fd.sysfile == nil { return 0, os.EINVAL } - if fd.wdeadline_delta > 0 { - fd.wdeadline = pollserver.Now() + fd.wdeadline_delta - } else { - fd.wdeadline = 0 - } nn := 0 for { @@ -539,11 +517,6 @@ func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err error) { defer fd.wio.Unlock() fd.incref() defer fd.decref() - if fd.wdeadline_delta > 0 { - fd.wdeadline = pollserver.Now() + fd.wdeadline_delta - } else { - fd.wdeadline = 0 - } for { err = syscall.Sendto(fd.sysfd, p, 0, sa) if err == syscall.EAGAIN { @@ -571,11 +544,6 @@ func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oob defer fd.wio.Unlock() fd.incref() defer fd.decref() - if fd.wdeadline_delta > 0 { - fd.wdeadline = pollserver.Now() + fd.wdeadline_delta - } else { - fd.wdeadline = 0 - } for { err = syscall.Sendmsg(fd.sysfd, p, oob, sa, 0) if err == syscall.EAGAIN { @@ -603,11 +571,6 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err err fd.incref() defer fd.decref() - if fd.rdeadline_delta > 0 { - fd.rdeadline = pollserver.Now() + fd.rdeadline_delta - } else { - fd.rdeadline = 0 - } // See ../syscall/exec.go for description of ForkLock. // It is okay to hold the lock across syscall.Accept @@ -636,7 +599,7 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err err syscall.CloseOnExec(s) syscall.ForkLock.RUnlock() - if nfd, err = newFD(s, fd.family, fd.proto, fd.net); err != nil { + if nfd, err = newFD(s, fd.family, fd.sotype, fd.net); err != nil { syscall.Close(s) return nil, err } diff --git a/libgo/go/net/fd_windows.go b/libgo/go/net/fd_windows.go index 7bffd1c..6e37b4e 100644 --- a/libgo/go/net/fd_windows.go +++ b/libgo/go/net/fd_windows.go @@ -150,12 +150,13 @@ func (s *ioSrv) ProcessRemoteIO() { } // ExecIO executes a single io operation. It either executes it -// inline, or, if timeouts are employed, passes the request onto +// inline, or, if a deadline is employed, passes the request onto // a special goroutine and waits for completion or cancels request. -func (s *ioSrv) ExecIO(oi anOpIface, deadline_delta int64) (n int, err error) { +// deadline is unix nanos. +func (s *ioSrv) ExecIO(oi anOpIface, deadline int64) (n int, err error) { var e error o := oi.Op() - if deadline_delta > 0 { + if deadline != 0 { // Send request to a special dedicated thread, // so it can stop the io with CancelIO later. s.submchan <- oi @@ -172,12 +173,17 @@ func (s *ioSrv) ExecIO(oi anOpIface, deadline_delta int64) (n int, err error) { return 0, &OpError{oi.Name(), o.fd.net, o.fd.laddr, e} } // Wait for our request to complete. - // TODO(rsc): This should stop the timer. var r ioResult - if deadline_delta > 0 { + if deadline != 0 { + dt := deadline - time.Now().UnixNano() + if dt < 1 { + dt = 1 + } + timer := time.NewTimer(time.Duration(dt) * time.Nanosecond) + defer timer.Stop() select { case r = <-o.resultc: - case <-time.After(time.Duration(deadline_delta) * time.Nanosecond): + case <-timer.C: s.canchan <- oi <-o.errnoc r = <-o.resultc @@ -224,7 +230,7 @@ type netFD struct { // immutable until Close sysfd syscall.Handle family int - proto int + sotype int net string laddr Addr raddr Addr @@ -232,19 +238,17 @@ type netFD struct { errnoc [2]chan error // read/write submit or cancel operation errors // owned by client - rdeadline_delta int64 - rdeadline int64 - rio sync.Mutex - wdeadline_delta int64 - wdeadline int64 - wio sync.Mutex + rdeadline int64 + rio sync.Mutex + wdeadline int64 + wio sync.Mutex } -func allocFD(fd syscall.Handle, family, proto int, net string) (f *netFD) { +func allocFD(fd syscall.Handle, family, sotype int, net string) (f *netFD) { f = &netFD{ sysfd: fd, family: family, - proto: proto, + sotype: sotype, net: net, } runtime.SetFinalizer(f, (*netFD).Close) @@ -357,7 +361,7 @@ func (fd *netFD) Read(buf []byte) (n int, err error) { } var o readOp o.Init(fd, buf, 'r') - n, err = iosrv.ExecIO(&o, fd.rdeadline_delta) + n, err = iosrv.ExecIO(&o, fd.rdeadline) if err == nil && n == 0 { err = io.EOF } @@ -398,7 +402,7 @@ func (fd *netFD) ReadFrom(buf []byte) (n int, sa syscall.Sockaddr, err error) { var o readFromOp o.Init(fd, buf, 'r') o.rsan = int32(unsafe.Sizeof(o.rsa)) - n, err = iosrv.ExecIO(&o, fd.rdeadline_delta) + n, err = iosrv.ExecIO(&o, fd.rdeadline) if err != nil { return 0, nil, err } @@ -434,7 +438,7 @@ func (fd *netFD) Write(buf []byte) (n int, err error) { } var o writeOp o.Init(fd, buf, 'w') - return iosrv.ExecIO(&o, fd.wdeadline_delta) + return iosrv.ExecIO(&o, fd.wdeadline) } // WriteTo to network. @@ -470,7 +474,7 @@ func (fd *netFD) WriteTo(buf []byte, sa syscall.Sockaddr) (n int, err error) { var o writeToOp o.Init(fd, buf, 'w') o.sa = sa - return iosrv.ExecIO(&o, fd.wdeadline_delta) + return iosrv.ExecIO(&o, fd.wdeadline) } // Accept new network connections. @@ -502,7 +506,7 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err err // Get new socket. // See ../syscall/exec.go for description of ForkLock. syscall.ForkLock.RLock() - s, e := syscall.Socket(fd.family, fd.proto, 0) + s, e := syscall.Socket(fd.family, fd.sotype, 0) if e != nil { syscall.ForkLock.RUnlock() return nil, e @@ -542,7 +546,7 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err err lsa, _ := lrsa.Sockaddr() rsa, _ := rrsa.Sockaddr() - nfd = allocFD(s, fd.family, fd.proto, fd.net) + nfd = allocFD(s, fd.family, fd.sotype, fd.net) nfd.setAddr(toAddr(lsa), toAddr(rsa)) return nfd, nil } diff --git a/libgo/go/net/http/cgi/host.go b/libgo/go/net/http/cgi/host.go index 615d366..73a9b6e 100644 --- a/libgo/go/net/http/cgi/host.go +++ b/libgo/go/net/http/cgi/host.go @@ -124,7 +124,7 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { "GATEWAY_INTERFACE=CGI/1.1", "REQUEST_METHOD=" + req.Method, "QUERY_STRING=" + req.URL.RawQuery, - "REQUEST_URI=" + req.URL.RawPath, + "REQUEST_URI=" + req.URL.RequestURI(), "PATH_INFO=" + pathInfo, "SCRIPT_NAME=" + root, "SCRIPT_FILENAME=" + h.Path, diff --git a/libgo/go/net/http/cgi/host_test.go b/libgo/go/net/http/cgi/host_test.go index 849cb00..b8dbdb4 100644 --- a/libgo/go/net/http/cgi/host_test.go +++ b/libgo/go/net/http/cgi/host_test.go @@ -364,7 +364,7 @@ func TestCopyError(t *testing.T) { conn.Close() tries := 0 - for tries < 15 && childRunning() { + for tries < 25 && childRunning() { time.Sleep(50 * time.Millisecond * time.Duration(tries)) tries++ } diff --git a/libgo/go/net/http/client.go b/libgo/go/net/http/client.go index a4f8f19..1d70672 100644 --- a/libgo/go/net/http/client.go +++ b/libgo/go/net/http/client.go @@ -24,11 +24,13 @@ import ( // The Client's Transport typically has internal state (cached // TCP connections), so Clients should be reused instead of created as // needed. Clients are safe for concurrent use by multiple goroutines. -// -// Client is not yet very configurable. type Client struct { - Transport RoundTripper // if nil, DefaultTransport is used + // Transport specifies the mechanism by which individual + // HTTP requests are made. + // If nil, DefaultTransport is used. + Transport RoundTripper + // CheckRedirect specifies the policy for handling redirects. // If CheckRedirect is not nil, the client calls it before // following an HTTP redirect. The arguments req and via // are the upcoming request and the requests made already, @@ -121,9 +123,8 @@ func send(req *Request, t RoundTripper) (resp *Response, err error) { req.Header = make(Header) } - info := req.URL.RawUserinfo - if len(info) > 0 { - req.Header.Set("Authorization", "Basic "+base64.URLEncoding.EncodeToString([]byte(info))) + if u := req.URL.User; u != nil { + req.Header.Set("Authorization", "Basic "+base64.URLEncoding.EncodeToString([]byte(u.String()))) } return t.RoundTrip(req) } @@ -213,11 +214,11 @@ func (c *Client) doFollowingRedirects(ireq *Request) (r *Response, err error) { break } } - for _, cookie := range jar.Cookies(req.URL) { - req.AddCookie(cookie) - } } + for _, cookie := range jar.Cookies(req.URL) { + req.AddCookie(cookie) + } urlStr = req.URL.String() if r, err = send(req, c.Transport); err != nil { break diff --git a/libgo/go/net/http/client_test.go b/libgo/go/net/http/client_test.go index 57a9dd9..c746110 100644 --- a/libgo/go/net/http/client_test.go +++ b/libgo/go/net/http/client_test.go @@ -18,6 +18,7 @@ import ( "net/url" "strconv" "strings" + "sync" "testing" ) @@ -236,6 +237,92 @@ func TestRedirects(t *testing.T) { } } +var expectedCookies = []*Cookie{ + &Cookie{Name: "ChocolateChip", Value: "tasty"}, + &Cookie{Name: "First", Value: "Hit"}, + &Cookie{Name: "Second", Value: "Hit"}, +} + +var echoCookiesRedirectHandler = HandlerFunc(func(w ResponseWriter, r *Request) { + for _, cookie := range r.Cookies() { + SetCookie(w, cookie) + } + if r.URL.Path == "/" { + SetCookie(w, expectedCookies[1]) + Redirect(w, r, "/second", StatusMovedPermanently) + } else { + SetCookie(w, expectedCookies[2]) + w.Write([]byte("hello")) + } +}) + +// Just enough correctness for our redirect tests. Uses the URL.Host as the +// scope of all cookies. +type TestJar struct { + m sync.Mutex + perURL map[string][]*Cookie +} + +func (j *TestJar) SetCookies(u *url.URL, cookies []*Cookie) { + j.m.Lock() + defer j.m.Unlock() + j.perURL[u.Host] = cookies +} + +func (j *TestJar) Cookies(u *url.URL) []*Cookie { + j.m.Lock() + defer j.m.Unlock() + return j.perURL[u.Host] +} + +func TestRedirectCookiesOnRequest(t *testing.T) { + var ts *httptest.Server + ts = httptest.NewServer(echoCookiesRedirectHandler) + defer ts.Close() + c := &Client{} + req, _ := NewRequest("GET", ts.URL, nil) + req.AddCookie(expectedCookies[0]) + // TODO: Uncomment when an implementation of a RFC6265 cookie jar lands. + _ = c + // resp, _ := c.Do(req) + // matchReturnedCookies(t, expectedCookies, resp.Cookies()) + + req, _ = NewRequest("GET", ts.URL, nil) + // resp, _ = c.Do(req) + // matchReturnedCookies(t, expectedCookies[1:], resp.Cookies()) +} + +func TestRedirectCookiesJar(t *testing.T) { + var ts *httptest.Server + ts = httptest.NewServer(echoCookiesRedirectHandler) + defer ts.Close() + c := &Client{} + c.Jar = &TestJar{perURL: make(map[string][]*Cookie)} + u, _ := url.Parse(ts.URL) + c.Jar.SetCookies(u, []*Cookie{expectedCookies[0]}) + resp, _ := c.Get(ts.URL) + matchReturnedCookies(t, expectedCookies, resp.Cookies()) +} + +func matchReturnedCookies(t *testing.T, expected, given []*Cookie) { + t.Logf("Received cookies: %v", given) + if len(given) != len(expected) { + t.Errorf("Expected %d cookies, got %d", len(expected), len(given)) + } + for _, ec := range expected { + foundC := false + for _, c := range given { + if ec.Name == c.Name && ec.Value == c.Value { + foundC = true + break + } + } + if !foundC { + t.Errorf("Missing cookie %v", ec) + } + } +} + func TestStreamingGet(t *testing.T) { say := make(chan string) ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { diff --git a/libgo/go/net/http/doc.go b/libgo/go/net/http/doc.go index 2dbcf8d..8962ed3 100644 --- a/libgo/go/net/http/doc.go +++ b/libgo/go/net/http/doc.go @@ -34,7 +34,8 @@ settings, create a Client: resp, err := client.Get("http://example.com") // ... - req := http.NewRequest("GET", "http://example.com", nil) + req, err := http.NewRequest("GET", "http://example.com", nil) + // ... req.Header.Add("If-None-Match", `W/"wyzzy"`) resp, err := client.Do(req) // ... diff --git a/libgo/go/net/http/fs_test.go b/libgo/go/net/http/fs_test.go index 976ee75..85cad3e 100644 --- a/libgo/go/net/http/fs_test.go +++ b/libgo/go/net/http/fs_test.go @@ -224,16 +224,15 @@ func TestEmptyDirOpenCWD(t *testing.T) { func TestServeFileContentType(t *testing.T) { const ctype = "icecream/chocolate" - override := false ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { - if override { + if r.FormValue("override") == "1" { w.Header().Set("Content-Type", ctype) } ServeFile(w, r, "testdata/file") })) defer ts.Close() - get := func(want string) { - resp, err := Get(ts.URL) + get := func(override, want string) { + resp, err := Get(ts.URL + "?override=" + override) if err != nil { t.Fatal(err) } @@ -241,9 +240,8 @@ func TestServeFileContentType(t *testing.T) { t.Errorf("Content-Type mismatch: got %q, want %q", h, want) } } - get("text/plain; charset=utf-8") - override = true - get(ctype) + get("0", "text/plain; charset=utf-8") + get("1", ctype) } func TestServeFileMimeType(t *testing.T) { diff --git a/libgo/go/net/http/httputil/dump.go b/libgo/go/net/http/httputil/dump.go index 31696ae..b8a98ee 100644 --- a/libgo/go/net/http/httputil/dump.go +++ b/libgo/go/net/http/httputil/dump.go @@ -13,6 +13,7 @@ import ( "net" "net/http" "strings" + "time" ) // One of the copies, say from b to r2, could be avoided by using a more @@ -36,12 +37,12 @@ type dumpConn struct { io.Reader } -func (c *dumpConn) Close() error { return nil } -func (c *dumpConn) LocalAddr() net.Addr { return nil } -func (c *dumpConn) RemoteAddr() net.Addr { return nil } -func (c *dumpConn) SetTimeout(nsec int64) error { return nil } -func (c *dumpConn) SetReadTimeout(nsec int64) error { return nil } -func (c *dumpConn) SetWriteTimeout(nsec int64) error { return nil } +func (c *dumpConn) Close() error { return nil } +func (c *dumpConn) LocalAddr() net.Addr { return nil } +func (c *dumpConn) RemoteAddr() net.Addr { return nil } +func (c *dumpConn) SetDeadline(t time.Time) error { return nil } +func (c *dumpConn) SetReadDeadline(t time.Time) error { return nil } +func (c *dumpConn) SetWriteDeadline(t time.Time) error { return nil } // DumpRequestOut is like DumpRequest but includes // headers that the standard http.Transport adds, @@ -124,16 +125,8 @@ func DumpRequest(req *http.Request, body bool) (dump []byte, err error) { var b bytes.Buffer - urlStr := req.URL.Raw - if urlStr == "" { - urlStr = valueOrDefault(req.URL.EncodedPath(), "/") - if req.URL.RawQuery != "" { - urlStr += "?" + req.URL.RawQuery - } - } - - fmt.Fprintf(&b, "%s %s HTTP/%d.%d\r\n", valueOrDefault(req.Method, "GET"), urlStr, - req.ProtoMajor, req.ProtoMinor) + fmt.Fprintf(&b, "%s %s HTTP/%d.%d\r\n", valueOrDefault(req.Method, "GET"), + req.URL.RequestURI(), req.ProtoMajor, req.ProtoMinor) host := req.Host if host == "" && req.URL != nil { diff --git a/libgo/go/net/http/httputil/reverseproxy.go b/libgo/go/net/http/httputil/reverseproxy.go index 1dc83e7..1072e2e 100644 --- a/libgo/go/net/http/httputil/reverseproxy.go +++ b/libgo/go/net/http/httputil/reverseproxy.go @@ -59,11 +59,6 @@ func NewSingleHostReverseProxy(target *url.URL) *ReverseProxy { req.URL.Scheme = target.Scheme req.URL.Host = target.Host req.URL.Path = singleJoiningSlash(target.Path, req.URL.Path) - if q := req.URL.RawQuery; q != "" { - req.URL.RawPath = req.URL.Path + "?" + q - } else { - req.URL.RawPath = req.URL.Path - } req.URL.RawQuery = target.RawQuery } return &ReverseProxy{Director: director} diff --git a/libgo/go/net/http/readrequest_test.go b/libgo/go/net/http/readrequest_test.go index ad7e3c0..da3e405 100644 --- a/libgo/go/net/http/readrequest_test.go +++ b/libgo/go/net/http/readrequest_test.go @@ -44,15 +44,9 @@ var reqTests = []reqTest{ &Request{ Method: "GET", URL: &url.URL{ - Raw: "http://www.techcrunch.com/", - Scheme: "http", - RawPath: "/", - RawAuthority: "www.techcrunch.com", - RawUserinfo: "", - Host: "www.techcrunch.com", - Path: "/", - RawQuery: "", - Fragment: "", + Scheme: "http", + Host: "www.techcrunch.com", + Path: "/", }, Proto: "HTTP/1.1", ProtoMajor: 1, @@ -86,9 +80,7 @@ var reqTests = []reqTest{ &Request{ Method: "GET", URL: &url.URL{ - Raw: "/", - Path: "/", - RawPath: "/", + Path: "/", }, Proto: "HTTP/1.1", ProtoMajor: 1, @@ -113,15 +105,7 @@ var reqTests = []reqTest{ &Request{ Method: "GET", URL: &url.URL{ - Raw: "//user@host/is/actually/a/path/", - Scheme: "", - RawPath: "//user@host/is/actually/a/path/", - RawAuthority: "", - RawUserinfo: "", - Host: "", - Path: "//user@host/is/actually/a/path/", - RawQuery: "", - Fragment: "", + Path: "//user@host/is/actually/a/path/", }, Proto: "HTTP/1.1", ProtoMajor: 1, @@ -170,9 +154,7 @@ var reqTests = []reqTest{ &Request{ Method: "POST", URL: &url.URL{ - Raw: "/", - Path: "/", - RawPath: "/", + Path: "/", }, TransferEncoding: []string{"chunked"}, Proto: "HTTP/1.1", diff --git a/libgo/go/net/http/request.go b/libgo/go/net/http/request.go index 2603010..5a4e739 100644 --- a/libgo/go/net/http/request.go +++ b/libgo/go/net/http/request.go @@ -302,26 +302,14 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header) err host = req.URL.Host } - urlStr := req.URL.RawPath - if strings.HasPrefix(urlStr, "?") { - urlStr = "/" + urlStr // Issue 2344 - } - if urlStr == "" { - urlStr = valueOrDefault(req.URL.RawPath, valueOrDefault(req.URL.EncodedPath(), "/")) - if req.URL.RawQuery != "" { - urlStr += "?" + req.URL.RawQuery - } - if usingProxy { - if urlStr == "" || urlStr[0] != '/' { - urlStr = "/" + urlStr - } - urlStr = req.URL.Scheme + "://" + host + urlStr - } + ruri := req.URL.RequestURI() + if usingProxy && req.URL.Scheme != "" && req.URL.Opaque == "" { + ruri = req.URL.Scheme + "://" + host + ruri } - // TODO(bradfitz): escape at least newlines in urlStr? + // TODO(bradfitz): escape at least newlines in ruri? bw := bufio.NewWriter(w) - fmt.Fprintf(bw, "%s %s HTTP/1.1\r\n", valueOrDefault(req.Method, "GET"), urlStr) + fmt.Fprintf(bw, "%s %s HTTP/1.1\r\n", valueOrDefault(req.Method, "GET"), ruri) // Header lines fmt.Fprintf(bw, "Host: %s\r\n", host) diff --git a/libgo/go/net/http/requestwrite_test.go b/libgo/go/net/http/requestwrite_test.go index 8081589..fc3186f 100644 --- a/libgo/go/net/http/requestwrite_test.go +++ b/libgo/go/net/http/requestwrite_test.go @@ -32,15 +32,9 @@ var reqWriteTests = []reqWriteTest{ Req: Request{ Method: "GET", URL: &url.URL{ - Raw: "http://www.techcrunch.com/", - Scheme: "http", - RawPath: "http://www.techcrunch.com/", - RawAuthority: "www.techcrunch.com", - RawUserinfo: "", - Host: "www.techcrunch.com", - Path: "/", - RawQuery: "", - Fragment: "", + Scheme: "http", + Host: "www.techcrunch.com", + Path: "/", }, Proto: "HTTP/1.1", ProtoMajor: 1, @@ -60,7 +54,7 @@ var reqWriteTests = []reqWriteTest{ Form: map[string][]string{}, }, - WantWrite: "GET http://www.techcrunch.com/ HTTP/1.1\r\n" + + WantWrite: "GET / HTTP/1.1\r\n" + "Host: www.techcrunch.com\r\n" + "User-Agent: Fake\r\n" + "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" + @@ -198,7 +192,7 @@ var reqWriteTests = []reqWriteTest{ "\r\n" + "abcdef", - WantProxy: "POST / HTTP/1.1\r\n" + + WantProxy: "POST http://example.com/ HTTP/1.1\r\n" + "Host: example.com\r\n" + "User-Agent: Go http package\r\n" + "Content-Length: 6\r\n" + diff --git a/libgo/go/net/http/serve_test.go b/libgo/go/net/http/serve_test.go index 24e6b50..147c216 100644 --- a/libgo/go/net/http/serve_test.go +++ b/libgo/go/net/http/serve_test.go @@ -84,15 +84,15 @@ func (c *testConn) RemoteAddr() net.Addr { return dummyAddr("remote-addr") } -func (c *testConn) SetTimeout(nsec int64) error { +func (c *testConn) SetDeadline(t time.Time) error { return nil } -func (c *testConn) SetReadTimeout(nsec int64) error { +func (c *testConn) SetReadDeadline(t time.Time) error { return nil } -func (c *testConn) SetWriteTimeout(nsec int64) error { +func (c *testConn) SetWriteDeadline(t time.Time) error { return nil } @@ -642,7 +642,7 @@ func TestServerExpect(t *testing.T) { // Note using r.FormValue("readbody") because for POST // requests that would read from r.Body, which we only // conditionally want to do. - if strings.Contains(r.URL.RawPath, "readbody=true") { + if strings.Contains(r.URL.RawQuery, "readbody=true") { ioutil.ReadAll(r.Body) w.Write([]byte("Hi")) } else { @@ -904,17 +904,13 @@ func testHandlerPanic(t *testing.T, withHijack bool) { panic("intentional death for testing") })) defer ts.Close() - _, err := Get(ts.URL) - if err == nil { - t.Logf("expected an error") - } // Do a blocking read on the log output pipe so its logging // doesn't bleed into the next test. But wait only 5 seconds // for it. - done := make(chan bool) + done := make(chan bool, 1) go func() { - buf := make([]byte, 1024) + buf := make([]byte, 4<<10) _, err := pr.Read(buf) pr.Close() if err != nil { @@ -922,6 +918,12 @@ func testHandlerPanic(t *testing.T, withHijack bool) { } done <- true }() + + _, err := Get(ts.URL) + if err == nil { + t.Logf("expected an error") + } + select { case <-done: return diff --git a/libgo/go/net/http/server.go b/libgo/go/net/http/server.go index fa90095..bad3bcb 100644 --- a/libgo/go/net/http/server.go +++ b/libgo/go/net/http/server.go @@ -569,14 +569,15 @@ func (c *conn) serve() { if err == nil { return } - if c.rwc != nil { // may be nil if connection hijacked - c.rwc.Close() - } var buf bytes.Buffer fmt.Fprintf(&buf, "http: panic serving %v: %v\n", c.remoteAddr, err) buf.Write(debug.Stack()) log.Print(buf.String()) + + if c.rwc != nil { // may be nil if connection hijacked + c.rwc.Close() + } }() if tlsConn, ok := c.rwc.(*tls.Conn); ok { @@ -954,8 +955,8 @@ func Serve(l net.Listener, handler Handler) error { type Server struct { Addr string // TCP address to listen on, ":http" if empty Handler Handler // handler to invoke, http.DefaultServeMux if nil - ReadTimeout time.Duration // the net.Conn.SetReadTimeout value for new connections - WriteTimeout time.Duration // the net.Conn.SetWriteTimeout value for new connections + ReadTimeout time.Duration // maximum duration before timing out read of the request + WriteTimeout time.Duration // maximum duration before timing out write of the response MaxHeaderBytes int // maximum size of request headers, DefaultMaxHeaderBytes if 0 } @@ -989,10 +990,10 @@ func (srv *Server) Serve(l net.Listener) error { return e } if srv.ReadTimeout != 0 { - rw.SetReadTimeout(srv.ReadTimeout.Nanoseconds()) + rw.SetReadDeadline(time.Now().Add(srv.ReadTimeout)) } if srv.WriteTimeout != 0 { - rw.SetWriteTimeout(srv.WriteTimeout.Nanoseconds()) + rw.SetWriteDeadline(time.Now().Add(srv.WriteTimeout)) } c, err := srv.newConn(rw) if err != nil { diff --git a/libgo/go/net/http/transport.go b/libgo/go/net/http/transport.go index 33ad328..1b9ad1b 100644 --- a/libgo/go/net/http/transport.go +++ b/libgo/go/net/http/transport.go @@ -229,9 +229,8 @@ func (cm *connectMethod) proxyAuth() string { if cm.proxyURL == nil { return "" } - proxyInfo := cm.proxyURL.RawUserinfo - if proxyInfo != "" { - return "Basic " + base64.URLEncoding.EncodeToString([]byte(proxyInfo)) + if u := cm.proxyURL.User; u != nil { + return "Basic " + base64.URLEncoding.EncodeToString([]byte(u.String())) } return "" } @@ -332,7 +331,7 @@ func (t *Transport) getConn(cm *connectMethod) (*persistConn, error) { case cm.targetScheme == "https": connectReq := &Request{ Method: "CONNECT", - URL: &url.URL{RawPath: cm.targetAddr}, + URL: &url.URL{Opaque: cm.targetAddr}, Host: cm.targetAddr, Header: make(Header), } diff --git a/libgo/go/net/ipraw_test.go b/libgo/go/net/ipraw_test.go index 67a4049..c74bfcd 100644 --- a/libgo/go/net/ipraw_test.go +++ b/libgo/go/net/ipraw_test.go @@ -12,6 +12,7 @@ import ( "flag" "os" "testing" + "time" ) const ICMP_ECHO_REQUEST = 8 @@ -101,7 +102,7 @@ func TestICMP(t *testing.T) { t.Fatalf(`net.WriteToIP(..., %v) = %v, %v`, raddr, n, err) } - c.SetTimeout(100e6) + c.SetDeadline(time.Now().Add(100 * time.Millisecond)) resp := make([]byte, 1024) for { n, from, err := c.ReadFrom(resp) diff --git a/libgo/go/net/iprawsock_plan9.go b/libgo/go/net/iprawsock_plan9.go index 3fd9dce..58df607 100644 --- a/libgo/go/net/iprawsock_plan9.go +++ b/libgo/go/net/iprawsock_plan9.go @@ -8,12 +8,28 @@ package net import ( "os" + "time" ) // IPConn is the implementation of the Conn and PacketConn // interfaces for IP network connections. type IPConn bool +// SetDeadline implements the net.Conn SetDeadline method. +func (c *IPConn) SetDeadline(t time.Time) error { + return os.EPLAN9 +} + +// SetReadDeadline implements the net.Conn SetReadDeadline method. +func (c *IPConn) SetReadDeadline(t time.Time) error { + return os.EPLAN9 +} + +// SetWriteDeadline implements the net.Conn SetWriteDeadline method. +func (c *IPConn) SetWriteDeadline(t time.Time) error { + return os.EPLAN9 +} + // Implementation of the Conn interface - see Conn for documentation. // Read implements the net.Conn Read method. @@ -41,21 +57,6 @@ func (c *IPConn) RemoteAddr() Addr { return nil } -// SetTimeout implements the net.Conn SetTimeout method. -func (c *IPConn) SetTimeout(nsec int64) error { - return os.EPLAN9 -} - -// SetReadTimeout implements the net.Conn SetReadTimeout method. -func (c *IPConn) SetReadTimeout(nsec int64) error { - return os.EPLAN9 -} - -// SetWriteTimeout implements the net.Conn SetWriteTimeout method. -func (c *IPConn) SetWriteTimeout(nsec int64) error { - return os.EPLAN9 -} - // IP-specific methods. // ReadFrom implements the net.PacketConn ReadFrom method. @@ -68,7 +69,7 @@ func (c *IPConn) ReadFrom(b []byte) (n int, addr Addr, err error) { // // WriteToIP can be made to time out and return // an error with Timeout() == true after a fixed time limit; -// see SetTimeout and SetWriteTimeout. +// see SetDeadline and SetWriteDeadline. // On packet-oriented connections, write timeouts are rare. func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (n int, err error) { return 0, os.EPLAN9 diff --git a/libgo/go/net/iprawsock_posix.go b/libgo/go/net/iprawsock_posix.go index 103c4f6..e4f755b 100644 --- a/libgo/go/net/iprawsock_posix.go +++ b/libgo/go/net/iprawsock_posix.go @@ -12,6 +12,7 @@ import ( "errors" "os" "syscall" + "time" ) func sockaddrToIP(sa syscall.Sockaddr) Addr { @@ -97,28 +98,28 @@ func (c *IPConn) RemoteAddr() Addr { return c.fd.raddr } -// SetTimeout implements the net.Conn SetTimeout method. -func (c *IPConn) SetTimeout(nsec int64) error { +// SetDeadline implements the net.Conn SetDeadline method. +func (c *IPConn) SetDeadline(t time.Time) error { if !c.ok() { return os.EINVAL } - return setTimeout(c.fd, nsec) + return setDeadline(c.fd, t) } -// SetReadTimeout implements the net.Conn SetReadTimeout method. -func (c *IPConn) SetReadTimeout(nsec int64) error { +// SetReadDeadline implements the net.Conn SetReadDeadline method. +func (c *IPConn) SetReadDeadline(t time.Time) error { if !c.ok() { return os.EINVAL } - return setReadTimeout(c.fd, nsec) + return setReadDeadline(c.fd, t) } -// SetWriteTimeout implements the net.Conn SetWriteTimeout method. -func (c *IPConn) SetWriteTimeout(nsec int64) error { +// SetWriteDeadline implements the net.Conn SetWriteDeadline method. +func (c *IPConn) SetWriteDeadline(t time.Time) error { if !c.ok() { return os.EINVAL } - return setWriteTimeout(c.fd, nsec) + return setWriteDeadline(c.fd, t) } // SetReadBuffer sets the size of the operating system's @@ -146,8 +147,8 @@ func (c *IPConn) SetWriteBuffer(bytes int) error { // that was on the packet. // // ReadFromIP can be made to time out and return an error with -// Timeout() == true after a fixed time limit; see SetTimeout and -// SetReadTimeout. +// Timeout() == true after a fixed time limit; see SetDeadline and +// SetReadDeadline. func (c *IPConn) ReadFromIP(b []byte) (n int, addr *IPAddr, err error) { if !c.ok() { return 0, nil, os.EINVAL @@ -182,7 +183,7 @@ func (c *IPConn) ReadFrom(b []byte) (n int, addr Addr, err error) { // // WriteToIP can be made to time out and return // an error with Timeout() == true after a fixed time limit; -// see SetTimeout and SetWriteTimeout. +// see SetDeadline and SetWriteDeadline. // On packet-oriented connections, write timeouts are rare. func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (n int, err error) { if !c.ok() { diff --git a/libgo/go/net/ipsock_plan9.go b/libgo/go/net/ipsock_plan9.go index 42fb408..09d8d6b 100644 --- a/libgo/go/net/ipsock_plan9.go +++ b/libgo/go/net/ipsock_plan9.go @@ -10,6 +10,7 @@ import ( "errors" "io" "os" + "time" ) // probeIPv6Stack returns two boolean values. If the first boolean value is @@ -156,27 +157,18 @@ func (c *plan9Conn) RemoteAddr() Addr { return c.raddr } -// SetTimeout implements the net.Conn SetTimeout method. -func (c *plan9Conn) SetTimeout(nsec int64) error { - if !c.ok() { - return os.EINVAL - } +// SetDeadline implements the net.Conn SetDeadline method. +func (c *plan9Conn) SetDeadline(t time.Time) error { return os.EPLAN9 } -// SetReadTimeout implements the net.Conn SetReadTimeout method. -func (c *plan9Conn) SetReadTimeout(nsec int64) error { - if !c.ok() { - return os.EINVAL - } +// SetReadDeadline implements the net.Conn SetReadDeadline method. +func (c *plan9Conn) SetReadDeadline(t time.Time) error { return os.EPLAN9 } -// SetWriteTimeout implements the net.Conn SetWriteTimeout method. -func (c *plan9Conn) SetWriteTimeout(nsec int64) error { - if !c.ok() { - return os.EINVAL - } +// SetWriteDeadline implements the net.Conn SetWriteDeadline method. +func (c *plan9Conn) SetWriteDeadline(t time.Time) error { return os.EPLAN9 } diff --git a/libgo/go/net/ipsock_posix.go b/libgo/go/net/ipsock_posix.go index 45fe0d9..3a059f5 100644 --- a/libgo/go/net/ipsock_posix.go +++ b/libgo/go/net/ipsock_posix.go @@ -101,7 +101,7 @@ type sockaddr interface { family() int } -func internetSocket(net string, laddr, raddr sockaddr, socktype, proto int, mode string, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err error) { +func internetSocket(net string, laddr, raddr sockaddr, sotype, proto int, mode string, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err error) { var oserr error var la, ra syscall.Sockaddr family := favoriteAddrFamily(net, raddr, laddr, mode) @@ -115,7 +115,7 @@ func internetSocket(net string, laddr, raddr sockaddr, socktype, proto int, mode goto Error } } - fd, oserr = socket(net, family, socktype, proto, la, ra, toAddr) + fd, oserr = socket(net, family, sotype, proto, la, ra, toAddr) if oserr != nil { goto Error } diff --git a/libgo/go/net/lookup_plan9.go b/libgo/go/net/lookup_plan9.go index 027794a..645aa6d 100644 --- a/libgo/go/net/lookup_plan9.go +++ b/libgo/go/net/lookup_plan9.go @@ -69,9 +69,7 @@ func queryDNS(addr string, typ string) (res []string, err error) { return query("/net/dns", addr+" "+typ, 1024) } -// LookupHost looks up the given host using the local resolver. -// It returns an array of that host's addresses. -func LookupHost(host string) (addrs []string, err error) { +func lookupHost(host string) (addrs []string, err error) { // Use /net/cs insead of /net/dns because cs knows about // host names in local network (e.g. from /lib/ndb/local) lines, err := queryCS("tcp", host, "1") @@ -95,9 +93,7 @@ func LookupHost(host string) (addrs []string, err error) { return } -// LookupIP looks up host using the local resolver. -// It returns an array of that host's IPv4 and IPv6 addresses. -func LookupIP(host string) (ips []IP, err error) { +func lookupIP(host string) (ips []IP, err error) { addrs, err := LookupHost(host) if err != nil { return @@ -110,8 +106,7 @@ func LookupIP(host string) (ips []IP, err error) { return } -// LookupPort looks up the port for the given network and service. -func LookupPort(network, service string) (port int, err error) { +func lookupPort(network, service string) (port int, err error) { switch network { case "tcp4", "tcp6": network = "tcp" @@ -140,11 +135,7 @@ func LookupPort(network, service string) (port int, err error) { return 0, unknownPortError } -// LookupCNAME returns the canonical DNS host for the given name. -// Callers that do not care about the canonical name can call -// LookupHost or LookupIP directly; both take care of resolving -// the canonical name as part of the lookup. -func LookupCNAME(name string) (cname string, err error) { +func lookupCNAME(name string) (cname string, err error) { lines, err := queryDNS(name, "cname") if err != nil { return @@ -157,16 +148,7 @@ func LookupCNAME(name string) (cname string, err error) { return "", errors.New("net: bad response from ndb/dns") } -// LookupSRV tries to resolve an SRV query of the given service, -// protocol, and domain name. The proto is "tcp" or "udp". -// The returned records are sorted by priority and randomized -// by weight within a priority. -// -// LookupSRV constructs the DNS name to look up following RFC 2782. -// That is, it looks up _service._proto.name. To accommodate services -// publishing SRV records under non-standard names, if both service -// and proto are empty strings, LookupSRV looks up name directly. -func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) { +func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) { var target string if service == "" && proto == "" { target = name @@ -195,8 +177,7 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err err return } -// LookupMX returns the DNS MX records for the given domain name sorted by preference. -func LookupMX(name string) (mx []*MX, err error) { +func lookupMX(name string) (mx []*MX, err error) { lines, err := queryDNS(name, "mx") if err != nil { return @@ -214,8 +195,7 @@ func LookupMX(name string) (mx []*MX, err error) { return } -// LookupTXT returns the DNS TXT records for the given domain name. -func LookupTXT(name string) (txt []string, err error) { +func lookupTXT(name string) (txt []string, err error) { lines, err := queryDNS(name, "txt") if err != nil { return @@ -228,9 +208,7 @@ func LookupTXT(name string) (txt []string, err error) { return } -// LookupAddr performs a reverse lookup for the given address, returning a list -// of names mapping to that address. -func LookupAddr(addr string) (name []string, err error) { +func lookupAddr(addr string) (name []string, err error) { arpa, err := reverseaddr(addr) if err != nil { return diff --git a/libgo/go/net/lookup_unix.go b/libgo/go/net/lookup_unix.go index 5c47547..d500a12 100644 --- a/libgo/go/net/lookup_unix.go +++ b/libgo/go/net/lookup_unix.go @@ -52,9 +52,7 @@ func lookupProtocol(name string) (proto int, err error) { return } -// LookupHost looks up the given host using the local resolver. -// It returns an array of that host's addresses. -func LookupHost(host string) (addrs []string, err error) { +func lookupHost(host string) (addrs []string, err error) { addrs, err, ok := cgoLookupHost(host) if !ok { addrs, err = goLookupHost(host) @@ -62,9 +60,7 @@ func LookupHost(host string) (addrs []string, err error) { return } -// LookupIP looks up host using the local resolver. -// It returns an array of that host's IPv4 and IPv6 addresses. -func LookupIP(host string) (addrs []IP, err error) { +func lookupIP(host string) (addrs []IP, err error) { addrs, err, ok := cgoLookupIP(host) if !ok { addrs, err = goLookupIP(host) @@ -72,8 +68,7 @@ func LookupIP(host string) (addrs []IP, err error) { return } -// LookupPort looks up the port for the given network and service. -func LookupPort(network, service string) (port int, err error) { +func lookupPort(network, service string) (port int, err error) { port, err, ok := cgoLookupPort(network, service) if !ok { port, err = goLookupPort(network, service) @@ -81,11 +76,7 @@ func LookupPort(network, service string) (port int, err error) { return } -// LookupCNAME returns the canonical DNS host for the given name. -// Callers that do not care about the canonical name can call -// LookupHost or LookupIP directly; both take care of resolving -// the canonical name as part of the lookup. -func LookupCNAME(name string) (cname string, err error) { +func lookupCNAME(name string) (cname string, err error) { cname, err, ok := cgoLookupCNAME(name) if !ok { cname, err = goLookupCNAME(name) @@ -93,16 +84,7 @@ func LookupCNAME(name string) (cname string, err error) { return } -// LookupSRV tries to resolve an SRV query of the given service, -// protocol, and domain name. The proto is "tcp" or "udp". -// The returned records are sorted by priority and randomized -// by weight within a priority. -// -// LookupSRV constructs the DNS name to look up following RFC 2782. -// That is, it looks up _service._proto.name. To accommodate services -// publishing SRV records under non-standard names, if both service -// and proto are empty strings, LookupSRV looks up name directly. -func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) { +func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) { var target string if service == "" && proto == "" { target = name @@ -123,8 +105,7 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err err return } -// LookupMX returns the DNS MX records for the given domain name sorted by preference. -func LookupMX(name string) (mx []*MX, err error) { +func lookupMX(name string) (mx []*MX, err error) { _, records, err := lookup(name, dnsTypeMX) if err != nil { return @@ -138,8 +119,7 @@ func LookupMX(name string) (mx []*MX, err error) { return } -// LookupTXT returns the DNS TXT records for the given domain name. -func LookupTXT(name string) (txt []string, err error) { +func lookupTXT(name string) (txt []string, err error) { _, records, err := lookup(name, dnsTypeTXT) if err != nil { return @@ -151,9 +131,7 @@ func LookupTXT(name string) (txt []string, err error) { return } -// LookupAddr performs a reverse lookup for the given address, returning a list -// of names mapping to that address. -func LookupAddr(addr string) (name []string, err error) { +func lookupAddr(addr string) (name []string, err error) { name = lookupStaticAddr(addr) if len(name) > 0 { return diff --git a/libgo/go/net/lookup_windows.go b/libgo/go/net/lookup_windows.go index 51afbd4..dfe2ff6 100644 --- a/libgo/go/net/lookup_windows.go +++ b/libgo/go/net/lookup_windows.go @@ -28,7 +28,7 @@ func lookupProtocol(name string) (proto int, err error) { return int(p.Proto), nil } -func LookupHost(name string) (addrs []string, err error) { +func lookupHost(name string) (addrs []string, err error) { ips, err := LookupIP(name) if err != nil { return @@ -40,7 +40,7 @@ func LookupHost(name string) (addrs []string, err error) { return } -func LookupIP(name string) (addrs []IP, err error) { +func lookupIP(name string) (addrs []IP, err error) { hostentLock.Lock() defer hostentLock.Unlock() h, e := syscall.GetHostByName(name) @@ -61,7 +61,7 @@ func LookupIP(name string) (addrs []IP, err error) { return addrs, nil } -func LookupPort(network, service string) (port int, err error) { +func lookupPort(network, service string) (port int, err error) { switch network { case "tcp4", "tcp6": network = "tcp" @@ -77,7 +77,7 @@ func LookupPort(network, service string) (port int, err error) { return int(syscall.Ntohs(s.Port)), nil } -func LookupCNAME(name string) (cname string, err error) { +func lookupCNAME(name string) (cname string, err error) { var r *syscall.DNSRecord e := syscall.DnsQuery(name, syscall.DNS_TYPE_CNAME, 0, nil, &r, nil) if e != nil { @@ -91,16 +91,7 @@ func LookupCNAME(name string) (cname string, err error) { return } -// LookupSRV tries to resolve an SRV query of the given service, -// protocol, and domain name. The proto is "tcp" or "udp". -// The returned records are sorted by priority and randomized -// by weight within a priority. -// -// LookupSRV constructs the DNS name to look up following RFC 2782. -// That is, it looks up _service._proto.name. To accommodate services -// publishing SRV records under non-standard names, if both service -// and proto are empty strings, LookupSRV looks up name directly. -func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) { +func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) { var target string if service == "" && proto == "" { target = name @@ -122,7 +113,7 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err err return name, addrs, nil } -func LookupMX(name string) (mx []*MX, err error) { +func lookupMX(name string) (mx []*MX, err error) { var r *syscall.DNSRecord e := syscall.DnsQuery(name, syscall.DNS_TYPE_MX, 0, nil, &r, nil) if e != nil { @@ -138,7 +129,7 @@ func LookupMX(name string) (mx []*MX, err error) { return mx, nil } -func LookupTXT(name string) (txt []string, err error) { +func lookupTXT(name string) (txt []string, err error) { var r *syscall.DNSRecord e := syscall.DnsQuery(name, syscall.DNS_TYPE_TEXT, 0, nil, &r, nil) if e != nil { @@ -156,7 +147,7 @@ func LookupTXT(name string) (txt []string, err error) { return } -func LookupAddr(addr string) (name []string, err error) { +func lookupAddr(addr string) (name []string, err error) { arpa, err := reverseaddr(addr) if err != nil { return nil, err diff --git a/libgo/go/net/net.go b/libgo/go/net/net.go index b236dfd..609fee2 100644 --- a/libgo/go/net/net.go +++ b/libgo/go/net/net.go @@ -9,7 +9,10 @@ package net // TODO(rsc): // support for raw ethernet sockets -import "errors" +import ( + "errors" + "time" +) // Addr represents a network end point address. type Addr interface { @@ -21,12 +24,12 @@ type Addr interface { type Conn interface { // Read reads data from the connection. // Read can be made to time out and return a net.Error with Timeout() == true - // after a fixed time limit; see SetTimeout and SetReadTimeout. + // after a fixed time limit; see SetDeadline and SetReadDeadline. Read(b []byte) (n int, err error) // Write writes data to the connection. // Write can be made to time out and return a net.Error with Timeout() == true - // after a fixed time limit; see SetTimeout and SetWriteTimeout. + // after a fixed time limit; see SetDeadline and SetWriteDeadline. Write(b []byte) (n int, err error) // Close closes the connection. @@ -38,21 +41,23 @@ type Conn interface { // RemoteAddr returns the remote network address. RemoteAddr() Addr - // SetTimeout sets the read and write deadlines associated + // SetDeadline sets the read and write deadlines associated // with the connection. - SetTimeout(nsec int64) error - - // SetReadTimeout sets the time (in nanoseconds) that - // Read will wait for data before returning an error with Timeout() == true. - // Setting nsec == 0 (the default) disables the deadline. - SetReadTimeout(nsec int64) error - - // SetWriteTimeout sets the time (in nanoseconds) that - // Write will wait to send its data before returning an error with Timeout() == true. - // Setting nsec == 0 (the default) disables the deadline. + SetDeadline(t time.Time) error + + // SetReadDeadline sets the deadline for all Read calls to return. + // If the deadline is reached, Read will fail with a timeout + // (see type Error) instead of blocking. + // A zero value for t means Read will not time out. + SetReadDeadline(t time.Time) error + + // SetWriteDeadline sets the deadline for all Write calls to return. + // If the deadline is reached, Write will fail with a timeout + // (see type Error) instead of blocking. + // A zero value for t means Write will not time out. // Even if write times out, it may return n > 0, indicating that // some of the data was successfully written. - SetWriteTimeout(nsec int64) error + SetWriteDeadline(t time.Time) error } // An Error represents a network error. @@ -70,13 +75,13 @@ type PacketConn interface { // was on the packet. // ReadFrom can be made to time out and return // an error with Timeout() == true after a fixed time limit; - // see SetTimeout and SetReadTimeout. + // see SetDeadline and SetReadDeadline. ReadFrom(b []byte) (n int, addr Addr, err error) // WriteTo writes a packet with payload b to addr. // WriteTo can be made to time out and return // an error with Timeout() == true after a fixed time limit; - // see SetTimeout and SetWriteTimeout. + // see SetDeadline and SetWriteDeadline. // On packet-oriented connections, write timeouts are rare. WriteTo(b []byte, addr Addr) (n int, err error) @@ -86,21 +91,23 @@ type PacketConn interface { // LocalAddr returns the local network address. LocalAddr() Addr - // SetTimeout sets the read and write deadlines associated + // SetDeadline sets the read and write deadlines associated // with the connection. - SetTimeout(nsec int64) error - - // SetReadTimeout sets the time (in nanoseconds) that - // Read will wait for data before returning an error with Timeout() == true. - // Setting nsec == 0 (the default) disables the deadline. - SetReadTimeout(nsec int64) error - - // SetWriteTimeout sets the time (in nanoseconds) that - // Write will wait to send its data before returning an error with Timeout() == true. - // Setting nsec == 0 (the default) disables the deadline. + SetDeadline(t time.Time) error + + // SetReadDeadline sets the deadline for all Read calls to return. + // If the deadline is reached, Read will fail with a timeout + // (see type Error) instead of blocking. + // A zero value for t means Read will not time out. + SetReadDeadline(t time.Time) error + + // SetWriteDeadline sets the deadline for all Write calls to return. + // If the deadline is reached, Write will fail with a timeout + // (see type Error) instead of blocking. + // A zero value for t means Write will not time out. // Even if write times out, it may return n > 0, indicating that // some of the data was successfully written. - SetWriteTimeout(nsec int64) error + SetWriteDeadline(t time.Time) error } // A Listener is a generic network listener for stream-oriented protocols. diff --git a/libgo/go/net/pipe.go b/libgo/go/net/pipe.go index 0ce7ccb..f1a2eca 100644 --- a/libgo/go/net/pipe.go +++ b/libgo/go/net/pipe.go @@ -7,6 +7,7 @@ package net import ( "errors" "io" + "time" ) // Pipe creates a synchronous, in-memory, full duplex @@ -53,14 +54,14 @@ func (p *pipe) RemoteAddr() Addr { return pipeAddr(0) } -func (p *pipe) SetTimeout(nsec int64) error { - return errors.New("net.Pipe does not support timeouts") +func (p *pipe) SetDeadline(t time.Time) error { + return errors.New("net.Pipe does not support deadlines") } -func (p *pipe) SetReadTimeout(nsec int64) error { - return errors.New("net.Pipe does not support timeouts") +func (p *pipe) SetReadDeadline(t time.Time) error { + return errors.New("net.Pipe does not support deadlines") } -func (p *pipe) SetWriteTimeout(nsec int64) error { - return errors.New("net.Pipe does not support timeouts") +func (p *pipe) SetWriteDeadline(t time.Time) error { + return errors.New("net.Pipe does not support deadlines") } diff --git a/libgo/go/net/sendfile_linux.go b/libgo/go/net/sendfile_linux.go index 350abe4..e9ab066 100644 --- a/libgo/go/net/sendfile_linux.go +++ b/libgo/go/net/sendfile_linux.go @@ -40,15 +40,6 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) { defer c.wio.Unlock() c.incref() defer c.decref() - if c.wdeadline_delta > 0 { - // This is a little odd that we're setting the timeout - // for the entire file but Write has the same issue - // (if one slurps the whole file into memory and - // do one large Write). At least they're consistent. - c.wdeadline = pollserver.Now() + c.wdeadline_delta - } else { - c.wdeadline = 0 - } dst := c.sysfd src := f.Fd() diff --git a/libgo/go/net/server_test.go b/libgo/go/net/server_test.go index 5475d38..b0b546b 100644 --- a/libgo/go/net/server_test.go +++ b/libgo/go/net/server_test.go @@ -11,6 +11,7 @@ import ( "runtime" "strings" "testing" + "time" ) // Do not test empty datagrams by default. @@ -63,7 +64,7 @@ func connect(t *testing.T, network, addr string, isEmpty bool) { if err != nil { t.Fatalf("net.Dial(%q, %q) = _, %v", network, addr, err) } - fd.SetReadTimeout(1e9) // 1s + fd.SetReadDeadline(time.Now().Add(1 * time.Second)) var b []byte if !isEmpty { @@ -91,7 +92,7 @@ func connect(t *testing.T, network, addr string, isEmpty bool) { } func doTest(t *testing.T, network, listenaddr, dialaddr string) { - t.Logf("Test %q %q %q\n", network, listenaddr, dialaddr) + t.Logf("Test %q %q %q", network, listenaddr, dialaddr) switch listenaddr { case "", "0.0.0.0", "[::]", "[::ffff:0.0.0.0]": if testing.Short() || avoidMacFirewall { @@ -169,10 +170,10 @@ func runPacket(t *testing.T, network, addr string, listening chan<- string, done t.Fatalf("net.ListenPacket(%q, %q) = _, %v", network, addr, err) } listening <- c.LocalAddr().String() - c.SetReadTimeout(10e6) // 10ms var buf [1000]byte Run: for { + c.SetReadDeadline(time.Now().Add(10 * time.Millisecond)) n, addr, err := c.ReadFrom(buf[0:]) if e, ok := err.(Error); ok && e.Timeout() { select { @@ -194,7 +195,7 @@ Run: } func doTestPacket(t *testing.T, network, listenaddr, dialaddr string, isEmpty bool) { - t.Logf("TestPacket %s %s %s\n", network, listenaddr, dialaddr) + t.Logf("TestPacket %q %q %q", network, listenaddr, dialaddr) listening := make(chan string) done := make(chan int) if network == "udp" { diff --git a/libgo/go/net/smtp/auth.go b/libgo/go/net/smtp/auth.go index 6f0cde0..d401e3c 100644 --- a/libgo/go/net/smtp/auth.go +++ b/libgo/go/net/smtp/auth.go @@ -6,6 +6,7 @@ package smtp import ( "crypto/hmac" + "crypto/md5" "errors" "fmt" ) @@ -88,7 +89,7 @@ func (a *cramMD5Auth) Start(server *ServerInfo) (string, []byte, error) { func (a *cramMD5Auth) Next(fromServer []byte, more bool) ([]byte, error) { if more { - d := hmac.NewMD5([]byte(a.secret)) + d := hmac.New(md5.New, []byte(a.secret)) d.Write(fromServer) s := make([]byte, 0, d.Size()) return []byte(fmt.Sprintf("%s %x", a.username, d.Sum(s))), nil diff --git a/libgo/go/net/sock.go b/libgo/go/net/sock.go index 881c922..2f3210b 100644 --- a/libgo/go/net/sock.go +++ b/libgo/go/net/sock.go @@ -17,10 +17,10 @@ import ( var listenerBacklog = maxListenerBacklog() // Generic socket creation. -func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err error) { +func socket(net string, f, t, p int, la, ra syscall.Sockaddr, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err error) { // See ../syscall/exec.go for description of ForkLock. syscall.ForkLock.RLock() - s, e := syscall.Socket(f, p, t) + s, err := syscall.Socket(f, t, p) if err != nil { syscall.ForkLock.RUnlock() return nil, err @@ -28,17 +28,17 @@ func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscal syscall.CloseOnExec(s) syscall.ForkLock.RUnlock() - setDefaultSockopts(s, f, p) + setDefaultSockopts(s, f, t) if la != nil { - e = syscall.Bind(s, la) - if e != nil { + err = syscall.Bind(s, la) + if err != nil { closesocket(s) - return nil, e + return nil, err } } - if fd, err = newFD(s, f, p, net); err != nil { + if fd, err = newFD(s, f, t, net); err != nil { closesocket(s) return nil, err } diff --git a/libgo/go/net/sockopt.go b/libgo/go/net/sockopt.go index 7fa1052..59f9af5 100644 --- a/libgo/go/net/sockopt.go +++ b/libgo/go/net/sockopt.go @@ -12,6 +12,7 @@ import ( "bytes" "os" "syscall" + "time" ) // Boolean to int. @@ -115,21 +116,21 @@ func setWriteBuffer(fd *netFD, bytes int) error { return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_SNDBUF, bytes)) } -func setReadTimeout(fd *netFD, nsec int64) error { - fd.rdeadline_delta = nsec +func setReadDeadline(fd *netFD, t time.Time) error { + fd.rdeadline = t.UnixNano() return nil } -func setWriteTimeout(fd *netFD, nsec int64) error { - fd.wdeadline_delta = nsec +func setWriteDeadline(fd *netFD, t time.Time) error { + fd.wdeadline = t.UnixNano() return nil } -func setTimeout(fd *netFD, nsec int64) error { - if e := setReadTimeout(fd, nsec); e != nil { +func setDeadline(fd *netFD, t time.Time) error { + if e := setReadDeadline(fd, t); e != nil { return e } - return setWriteTimeout(fd, nsec) + return setWriteDeadline(fd, t) } func setReuseAddr(fd *netFD, reuse bool) error { diff --git a/libgo/go/net/sockopt_bsd.go b/libgo/go/net/sockopt_bsd.go index e99fb41..2093e08 100644 --- a/libgo/go/net/sockopt_bsd.go +++ b/libgo/go/net/sockopt_bsd.go @@ -12,14 +12,15 @@ import ( "syscall" ) -func setDefaultSockopts(s, f, p int) { +func setDefaultSockopts(s, f, t int) { switch f { case syscall.AF_INET6: // Allow both IP versions even if the OS default is otherwise. syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0) } - if f == syscall.AF_UNIX || p == syscall.IPPROTO_TCP { + if f == syscall.AF_UNIX || + (f == syscall.AF_INET || f == syscall.AF_INET6) && t == syscall.SOCK_STREAM { // Allow reuse of recently-used addresses. syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1) diff --git a/libgo/go/net/sockopt_linux.go b/libgo/go/net/sockopt_linux.go index 5158384..9dbb4e5 100644 --- a/libgo/go/net/sockopt_linux.go +++ b/libgo/go/net/sockopt_linux.go @@ -10,14 +10,15 @@ import ( "syscall" ) -func setDefaultSockopts(s, f, p int) { +func setDefaultSockopts(s, f, t int) { switch f { case syscall.AF_INET6: // Allow both IP versions even if the OS default is otherwise. syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0) } - if f == syscall.AF_UNIX || p == syscall.IPPROTO_TCP { + if f == syscall.AF_UNIX || + (f == syscall.AF_INET || f == syscall.AF_INET6) && t == syscall.SOCK_STREAM { // Allow reuse of recently-used addresses. syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1) } diff --git a/libgo/go/net/sockopt_windows.go b/libgo/go/net/sockopt_windows.go index 485c14a..a7b5606 100644 --- a/libgo/go/net/sockopt_windows.go +++ b/libgo/go/net/sockopt_windows.go @@ -10,7 +10,7 @@ import ( "syscall" ) -func setDefaultSockopts(s syscall.Handle, f, p int) { +func setDefaultSockopts(s syscall.Handle, f, t int) { switch f { case syscall.AF_INET6: // Allow both IP versions even if the OS default is otherwise. diff --git a/libgo/go/net/tcpsock_plan9.go b/libgo/go/net/tcpsock_plan9.go index 69fae03..288ec05 100644 --- a/libgo/go/net/tcpsock_plan9.go +++ b/libgo/go/net/tcpsock_plan9.go @@ -8,6 +8,7 @@ package net import ( "os" + "time" ) // TCPConn is an implementation of the Conn interface @@ -16,6 +17,21 @@ type TCPConn struct { plan9Conn } +// SetDeadline implements the net.Conn SetDeadline method. +func (c *TCPConn) SetDeadline(t time.Time) error { + return os.EPLAN9 +} + +// SetReadDeadline implements the net.Conn SetReadDeadline method. +func (c *TCPConn) SetReadDeadline(t time.Time) error { + return os.EPLAN9 +} + +// SetWriteDeadline implements the net.Conn SetWriteDeadline method. +func (c *TCPConn) SetWriteDeadline(t time.Time) error { + return os.EPLAN9 +} + // CloseRead shuts down the reading side of the TCP connection. // Most callers should just use Close. func (c *TCPConn) CloseRead() error { diff --git a/libgo/go/net/tcpsock_posix.go b/libgo/go/net/tcpsock_posix.go index a492e61..91816fa 100644 --- a/libgo/go/net/tcpsock_posix.go +++ b/libgo/go/net/tcpsock_posix.go @@ -12,6 +12,7 @@ import ( "io" "os" "syscall" + "time" ) // BUG(rsc): On OpenBSD, listening on the "tcp" network does not listen for @@ -134,28 +135,28 @@ func (c *TCPConn) RemoteAddr() Addr { return c.fd.raddr } -// SetTimeout implements the net.Conn SetTimeout method. -func (c *TCPConn) SetTimeout(nsec int64) error { +// SetDeadline implements the net.Conn SetDeadline method. +func (c *TCPConn) SetDeadline(t time.Time) error { if !c.ok() { return os.EINVAL } - return setTimeout(c.fd, nsec) + return setDeadline(c.fd, t) } -// SetReadTimeout implements the net.Conn SetReadTimeout method. -func (c *TCPConn) SetReadTimeout(nsec int64) error { +// SetReadDeadline implements the net.Conn SetReadDeadline method. +func (c *TCPConn) SetReadDeadline(t time.Time) error { if !c.ok() { return os.EINVAL } - return setReadTimeout(c.fd, nsec) + return setReadDeadline(c.fd, t) } -// SetWriteTimeout implements the net.Conn SetWriteTimeout method. -func (c *TCPConn) SetWriteTimeout(nsec int64) error { +// SetWriteDeadline implements the net.Conn SetWriteDeadline method. +func (c *TCPConn) SetWriteDeadline(t time.Time) error { if !c.ok() { return os.EINVAL } - return setWriteTimeout(c.fd, nsec) + return setWriteDeadline(c.fd, t) } // SetReadBuffer sets the size of the operating system's @@ -294,12 +295,13 @@ func (l *TCPListener) Close() error { // Addr returns the listener's network address, a *TCPAddr. func (l *TCPListener) Addr() Addr { return l.fd.laddr } -// SetTimeout sets the deadline associated with the listener -func (l *TCPListener) SetTimeout(nsec int64) error { +// SetDeadline sets the deadline associated with the listener. +// A zero time value disables the deadline. +func (l *TCPListener) SetDeadline(t time.Time) error { if l == nil || l.fd == nil { return os.EINVAL } - return setTimeout(l.fd, nsec) + return setDeadline(l.fd, t) } // File returns a copy of the underlying os.File, set to blocking mode. diff --git a/libgo/go/net/timeout_test.go b/libgo/go/net/timeout_test.go index f6e5238..11db012 100644 --- a/libgo/go/net/timeout_test.go +++ b/libgo/go/net/timeout_test.go @@ -5,6 +5,7 @@ package net import ( + "fmt" "runtime" "testing" "time" @@ -17,26 +18,41 @@ func testTimeout(t *testing.T, network, addr string, readFrom bool) { return } defer fd.Close() - t0 := time.Now() - fd.SetReadTimeout(1e8) // 100ms - var b [100]byte - var n int - var err1 error - if readFrom { - n, _, err1 = fd.(PacketConn).ReadFrom(b[0:]) - } else { - n, err1 = fd.Read(b[0:]) - } - t1 := time.Now() what := "Read" if readFrom { what = "ReadFrom" } - if n != 0 || err1 == nil || !err1.(Error).Timeout() { - t.Errorf("fd.%s on %s %s did not return 0, timeout: %v, %v", what, network, addr, n, err1) - } - if dt := t1.Sub(t0); dt < 50*time.Millisecond || dt > 150*time.Millisecond { - t.Errorf("fd.%s on %s %s took %s, expected 0.1s", what, network, addr, dt) + + errc := make(chan error, 1) + go func() { + t0 := time.Now() + fd.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) + var b [100]byte + var n int + var err1 error + if readFrom { + n, _, err1 = fd.(PacketConn).ReadFrom(b[0:]) + } else { + n, err1 = fd.Read(b[0:]) + } + t1 := time.Now() + if n != 0 || err1 == nil || !err1.(Error).Timeout() { + errc <- fmt.Errorf("fd.%s on %s %s did not return 0, timeout: %v, %v", what, network, addr, n, err1) + return + } + if dt := t1.Sub(t0); dt < 50*time.Millisecond || dt > 250*time.Millisecond { + errc <- fmt.Errorf("fd.%s on %s %s took %s, expected 0.1s", what, network, addr, dt) + return + } + errc <- nil + }() + select { + case err := <-errc: + if err != nil { + t.Error(err) + } + case <-time.After(1 * time.Second): + t.Errorf("%s on %s %s took over 1 second, expected 0.1s", what, network, addr) } } diff --git a/libgo/go/net/udpsock_plan9.go b/libgo/go/net/udpsock_plan9.go index 60dec81..246c9ad 100644 --- a/libgo/go/net/udpsock_plan9.go +++ b/libgo/go/net/udpsock_plan9.go @@ -9,6 +9,7 @@ package net import ( "errors" "os" + "time" ) // UDPConn is the implementation of the Conn and PacketConn @@ -17,6 +18,21 @@ type UDPConn struct { plan9Conn } +// SetDeadline implements the net.Conn SetDeadline method. +func (c *UDPConn) SetDeadline(t time.Time) error { + return os.EPLAN9 +} + +// SetReadDeadline implements the net.Conn SetReadDeadline method. +func (c *UDPConn) SetReadDeadline(t time.Time) error { + return os.EPLAN9 +} + +// SetWriteDeadline implements the net.Conn SetWriteDeadline method. +func (c *UDPConn) SetWriteDeadline(t time.Time) error { + return os.EPLAN9 +} + // UDP-specific methods. // ReadFromUDP reads a UDP packet from c, copying the payload into b. @@ -24,7 +40,7 @@ type UDPConn struct { // that was on the packet. // // ReadFromUDP can be made to time out and return an error with Timeout() == true -// after a fixed time limit; see SetTimeout and SetReadTimeout. +// after a fixed time limit; see SetDeadline and SetReadDeadline. func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) { if !c.ok() { return 0, nil, os.EINVAL @@ -62,7 +78,7 @@ func (c *UDPConn) ReadFrom(b []byte) (n int, addr Addr, err error) { // // WriteToUDP can be made to time out and return // an error with Timeout() == true after a fixed time limit; -// see SetTimeout and SetWriteTimeout. +// see SetDeadline and SetWriteDeadline. // On packet-oriented connections, write timeouts are rare. func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (n int, err error) { if !c.ok() { diff --git a/libgo/go/net/udpsock_posix.go b/libgo/go/net/udpsock_posix.go index d0bdb14..0b5bc16 100644 --- a/libgo/go/net/udpsock_posix.go +++ b/libgo/go/net/udpsock_posix.go @@ -11,6 +11,7 @@ package net import ( "os" "syscall" + "time" ) func sockaddrToUDP(sa syscall.Sockaddr) Addr { @@ -98,28 +99,28 @@ func (c *UDPConn) RemoteAddr() Addr { return c.fd.raddr } -// SetTimeout implements the net.Conn SetTimeout method. -func (c *UDPConn) SetTimeout(nsec int64) error { +// SetDeadline implements the net.Conn SetDeadline method. +func (c *UDPConn) SetDeadline(t time.Time) error { if !c.ok() { return os.EINVAL } - return setTimeout(c.fd, nsec) + return setDeadline(c.fd, t) } -// SetReadTimeout implements the net.Conn SetReadTimeout method. -func (c *UDPConn) SetReadTimeout(nsec int64) error { +// SetReadDeadline implements the net.Conn SetReadDeadline method. +func (c *UDPConn) SetReadDeadline(t time.Time) error { if !c.ok() { return os.EINVAL } - return setReadTimeout(c.fd, nsec) + return setReadDeadline(c.fd, t) } -// SetWriteTimeout implements the net.Conn SetWriteTimeout method. -func (c *UDPConn) SetWriteTimeout(nsec int64) error { +// SetWriteDeadline implements the net.Conn SetWriteDeadline method. +func (c *UDPConn) SetWriteDeadline(t time.Time) error { if !c.ok() { return os.EINVAL } - return setWriteTimeout(c.fd, nsec) + return setWriteDeadline(c.fd, t) } // SetReadBuffer sets the size of the operating system's @@ -147,7 +148,7 @@ func (c *UDPConn) SetWriteBuffer(bytes int) error { // that was on the packet. // // ReadFromUDP can be made to time out and return an error with Timeout() == true -// after a fixed time limit; see SetTimeout and SetReadTimeout. +// after a fixed time limit; see SetDeadline and SetReadDeadline. func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) { if !c.ok() { return 0, nil, os.EINVAL @@ -175,7 +176,7 @@ func (c *UDPConn) ReadFrom(b []byte) (n int, addr Addr, err error) { // // WriteToUDP can be made to time out and return // an error with Timeout() == true after a fixed time limit; -// see SetTimeout and SetWriteTimeout. +// see SetDeadline and SetWriteDeadline. // On packet-oriented connections, write timeouts are rare. func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (n int, err error) { if !c.ok() { diff --git a/libgo/go/net/unicast_test.go b/libgo/go/net/unicast_test.go index 6ed6f59..297276d 100644 --- a/libgo/go/net/unicast_test.go +++ b/libgo/go/net/unicast_test.go @@ -5,6 +5,7 @@ package net import ( + "io" "runtime" "testing" ) @@ -15,10 +16,12 @@ var unicastTests = []struct { ipv6 bool packet bool }{ - {"tcp4", "127.0.0.1:0", false, false}, - {"tcp6", "[::1]:0", true, false}, - {"udp4", "127.0.0.1:0", false, true}, - {"udp6", "[::1]:0", true, true}, + {net: "tcp4", laddr: "127.0.0.1:0"}, + {net: "tcp4", laddr: "previous"}, + {net: "tcp6", laddr: "[::1]:0", ipv6: true}, + {net: "tcp6", laddr: "previous", ipv6: true}, + {net: "udp4", laddr: "127.0.0.1:0", packet: true}, + {net: "udp6", laddr: "[::1]:0", ipv6: true, packet: true}, } func TestUnicastTCPAndUDP(t *testing.T) { @@ -26,24 +29,32 @@ func TestUnicastTCPAndUDP(t *testing.T) { return } + prevladdr := "" for _, tt := range unicastTests { if tt.ipv6 && !supportsIPv6 { continue } - var fd *netFD + var ( + fd *netFD + closer io.Closer + ) if !tt.packet { - c, err := Listen(tt.net, tt.laddr) + if tt.laddr == "previous" { + tt.laddr = prevladdr + } + l, err := Listen(tt.net, tt.laddr) if err != nil { t.Fatalf("Listen failed: %v", err) } - defer c.Close() - fd = c.(*TCPListener).fd + prevladdr = l.Addr().String() + closer = l + fd = l.(*TCPListener).fd } else { c, err := ListenPacket(tt.net, tt.laddr) if err != nil { t.Fatalf("ListenPacket failed: %v", err) } - defer c.Close() + closer = c fd = c.(*UDPConn).fd } if !tt.ipv6 { @@ -51,6 +62,7 @@ func TestUnicastTCPAndUDP(t *testing.T) { } else { testIPv6UnicastSocketOptions(t, fd) } + closer.Close() } } diff --git a/libgo/go/net/unixsock_plan9.go b/libgo/go/net/unixsock_plan9.go index ac502d1..e8087d0 100644 --- a/libgo/go/net/unixsock_plan9.go +++ b/libgo/go/net/unixsock_plan9.go @@ -8,6 +8,7 @@ package net import ( "os" + "time" ) // UnixConn is an implementation of the Conn interface @@ -44,18 +45,18 @@ func (c *UnixConn) RemoteAddr() Addr { return nil } -// SetTimeout implements the net.Conn SetTimeout method. -func (c *UnixConn) SetTimeout(nsec int64) error { +// SetDeadline implements the net.Conn SetDeadline method. +func (c *UnixConn) SetDeadline(t time.Time) error { return os.EPLAN9 } -// SetReadTimeout implements the net.Conn SetReadTimeout method. -func (c *UnixConn) SetReadTimeout(nsec int64) error { +// SetReadDeadline implements the net.Conn SetReadDeadline method. +func (c *UnixConn) SetReadDeadline(t time.Time) error { return os.EPLAN9 } -// SetWriteTimeout implements the net.Conn SetWriteTimeout method. -func (c *UnixConn) SetWriteTimeout(nsec int64) error { +// SetWriteDeadline implements the net.Conn SetWriteDeadline method. +func (c *UnixConn) SetWriteDeadline(t time.Time) error { return os.EPLAN9 } diff --git a/libgo/go/net/unixsock_posix.go b/libgo/go/net/unixsock_posix.go index 00ee016..5b8b2e4 100644 --- a/libgo/go/net/unixsock_posix.go +++ b/libgo/go/net/unixsock_posix.go @@ -11,19 +11,20 @@ package net import ( "os" "syscall" + "time" ) func unixSocket(net string, laddr, raddr *UnixAddr, mode string) (fd *netFD, err error) { - var proto int + var sotype int switch net { default: return nil, UnknownNetworkError(net) case "unix": - proto = syscall.SOCK_STREAM + sotype = syscall.SOCK_STREAM case "unixgram": - proto = syscall.SOCK_DGRAM + sotype = syscall.SOCK_DGRAM case "unixpacket": - proto = syscall.SOCK_SEQPACKET + sotype = syscall.SOCK_SEQPACKET } var la, ra syscall.Sockaddr @@ -37,7 +38,7 @@ func unixSocket(net string, laddr, raddr *UnixAddr, mode string) (fd *netFD, err } if raddr != nil { ra = &syscall.SockaddrUnix{Name: raddr.Name} - } else if proto != syscall.SOCK_DGRAM || laddr == nil { + } else if sotype != syscall.SOCK_DGRAM || laddr == nil { return nil, &OpError{Op: mode, Net: net, Err: errMissingAddress} } @@ -52,13 +53,13 @@ func unixSocket(net string, laddr, raddr *UnixAddr, mode string) (fd *netFD, err } f := sockaddrToUnix - if proto == syscall.SOCK_DGRAM { + if sotype == syscall.SOCK_DGRAM { f = sockaddrToUnixgram - } else if proto == syscall.SOCK_SEQPACKET { + } else if sotype == syscall.SOCK_SEQPACKET { f = sockaddrToUnixpacket } - fd, oserr := socket(net, syscall.AF_UNIX, proto, 0, la, ra, f) + fd, oserr := socket(net, syscall.AF_UNIX, sotype, 0, la, ra, f) if oserr != nil { goto Error } @@ -93,8 +94,8 @@ func sockaddrToUnixpacket(sa syscall.Sockaddr) Addr { return nil } -func protoToNet(proto int) string { - switch proto { +func sotypeToNet(sotype int) string { + switch sotype { case syscall.SOCK_STREAM: return "unix" case syscall.SOCK_SEQPACKET: @@ -102,7 +103,7 @@ func protoToNet(proto int) string { case syscall.SOCK_DGRAM: return "unixgram" default: - panic("protoToNet unknown protocol") + panic("sotypeToNet unknown socket type") } return "" } @@ -164,28 +165,28 @@ func (c *UnixConn) RemoteAddr() Addr { return c.fd.raddr } -// SetTimeout implements the net.Conn SetTimeout method. -func (c *UnixConn) SetTimeout(nsec int64) error { +// SetDeadline implements the net.Conn SetDeadline method. +func (c *UnixConn) SetDeadline(t time.Time) error { if !c.ok() { return os.EINVAL } - return setTimeout(c.fd, nsec) + return setDeadline(c.fd, t) } -// SetReadTimeout implements the net.Conn SetReadTimeout method. -func (c *UnixConn) SetReadTimeout(nsec int64) error { +// SetReadDeadline implements the net.Conn SetReadDeadline method. +func (c *UnixConn) SetReadDeadline(t time.Time) error { if !c.ok() { return os.EINVAL } - return setReadTimeout(c.fd, nsec) + return setReadDeadline(c.fd, t) } -// SetWriteTimeout implements the net.Conn SetWriteTimeout method. -func (c *UnixConn) SetWriteTimeout(nsec int64) error { +// SetWriteDeadline implements the net.Conn SetWriteDeadline method. +func (c *UnixConn) SetWriteDeadline(t time.Time) error { if !c.ok() { return os.EINVAL } - return setWriteTimeout(c.fd, nsec) + return setWriteDeadline(c.fd, t) } // SetReadBuffer sets the size of the operating system's @@ -212,7 +213,7 @@ func (c *UnixConn) SetWriteBuffer(bytes int) error { // // ReadFromUnix can be made to time out and return // an error with Timeout() == true after a fixed time limit; -// see SetTimeout and SetReadTimeout. +// see SetDeadline and SetReadDeadline. func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err error) { if !c.ok() { return 0, nil, os.EINVAL @@ -220,7 +221,7 @@ func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err error) { n, sa, err := c.fd.ReadFrom(b) switch sa := sa.(type) { case *syscall.SockaddrUnix: - addr = &UnixAddr{sa.Name, protoToNet(c.fd.proto)} + addr = &UnixAddr{sa.Name, sotypeToNet(c.fd.sotype)} } return } @@ -238,13 +239,13 @@ func (c *UnixConn) ReadFrom(b []byte) (n int, addr Addr, err error) { // // WriteToUnix can be made to time out and return // an error with Timeout() == true after a fixed time limit; -// see SetTimeout and SetWriteTimeout. +// see SetDeadline and SetWriteDeadline. // On packet-oriented connections, write timeouts are rare. func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (n int, err error) { if !c.ok() { return 0, os.EINVAL } - if addr.Net != protoToNet(c.fd.proto) { + if addr.Net != sotypeToNet(c.fd.sotype) { return 0, os.EAFNOSUPPORT } sa := &syscall.SockaddrUnix{Name: addr.Name} @@ -270,7 +271,7 @@ func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAdd n, oobn, flags, sa, err := c.fd.ReadMsg(b, oob) switch sa := sa.(type) { case *syscall.SockaddrUnix: - addr = &UnixAddr{sa.Name, protoToNet(c.fd.proto)} + addr = &UnixAddr{sa.Name, sotypeToNet(c.fd.sotype)} } return } @@ -280,7 +281,7 @@ func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err return 0, 0, os.EINVAL } if addr != nil { - if addr.Net != protoToNet(c.fd.proto) { + if addr.Net != sotypeToNet(c.fd.sotype) { return 0, 0, os.EAFNOSUPPORT } sa := &syscall.SockaddrUnix{Name: addr.Name} @@ -386,12 +387,13 @@ func (l *UnixListener) Close() error { // Addr returns the listener's network address. func (l *UnixListener) Addr() Addr { return l.fd.laddr } -// SetTimeout sets the deadline associated wuth the listener -func (l *UnixListener) SetTimeout(nsec int64) (err error) { +// SetDeadline sets the deadline associated with the listener. +// A zero time value disables the deadline. +func (l *UnixListener) SetDeadline(t time.Time) (err error) { if l == nil || l.fd == nil { return os.EINVAL } - return setTimeout(l.fd, nsec) + return setDeadline(l.fd, t) } // File returns a copy of the underlying os.File, set to blocking mode. diff --git a/libgo/go/net/url/url.go b/libgo/go/net/url/url.go index 11fa189..0068e98 100644 --- a/libgo/go/net/url/url.go +++ b/libgo/go/net/url/url.go @@ -52,7 +52,6 @@ const ( encodeUserPassword encodeQueryComponent encodeFragment - encodeOpaque ) type EscapeError string @@ -69,6 +68,7 @@ func shouldEscape(c byte, mode encoding) bool { if 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' { return false } + // TODO: Update the character sets after RFC 3986. switch c { case '-', '_', '.', '!', '~', '*', '\'', '(', ')': // §2.3 Unreserved characters (mark) return false @@ -78,12 +78,10 @@ func shouldEscape(c byte, mode encoding) bool { // the reserved characters to appear unescaped. switch mode { case encodePath: // §3.3 - // The RFC allows : @ & = + $ , but saves / ; for assigning - // meaning to individual path segments. This package + // The RFC allows : @ & = + $ but saves / ; , for assigning + // meaning to individual path segments. This package // only manipulates the path as a whole, so we allow those - // last two as well. Clients that need to distinguish between - // `/foo;y=z/bar` and `/foo%3by=z/bar` will have to re-decode RawPath. - // That leaves only ? to escape. + // last two as well. That leaves only ? to escape. return c == '?' case encodeUserPassword: // §3.2.2 @@ -99,12 +97,6 @@ func shouldEscape(c byte, mode encoding) bool { // The RFC text is silent but the grammar allows // everything, so escape nothing. return false - - case encodeOpaque: // §3 opaque_part - // The RFC allows opaque_part to use all characters - // except that the leading / must be escaped. - // (We implement that case in String.) - return false } } @@ -217,64 +209,73 @@ func escape(s string, mode encoding) string { return string(t) } -// UnescapeUserinfo parses the RawUserinfo field of a URL -// as the form user or user:password and unescapes and returns -// the two halves. +// A URL represents a parsed URL (technically, a URI reference). +// The general form represented is: // -// This functionality should only be used with legacy web sites. -// RFC 2396 warns that interpreting Userinfo this way -// ``is NOT RECOMMENDED, because the passing of authentication -// information in clear text (such as URI) has proven to be a -// security risk in almost every case where it has been used.'' -func UnescapeUserinfo(rawUserinfo string) (user, password string, err error) { - u, p := split(rawUserinfo, ':', true) - if user, err = unescape(u, encodeUserPassword); err != nil { - return "", "", err - } - if password, err = unescape(p, encodeUserPassword); err != nil { - return "", "", err - } - return +// scheme://[userinfo@]host/path[?query][#fragment] +// +// URLs that do not start with a slash after the scheme are interpreted as: +// +// scheme:opaque[?query][#fragment] +// +type URL struct { + Scheme string + Opaque string // encoded opaque data + User *Userinfo // username and password information + Host string + Path string + RawQuery string // encoded query values, without '?' + Fragment string // fragment for references, without '#' } -// EscapeUserinfo combines user and password in the form -// user:password (or just user if password is empty) and then -// escapes it for use as the URL.RawUserinfo field. -// +// User returns a Userinfo containing the provided username +// and no password set. +func User(username string) *Userinfo { + return &Userinfo{username, "", false} +} + +// UserPassword returns a Userinfo containing the provided username +// and password. // This functionality should only be used with legacy web sites. // RFC 2396 warns that interpreting Userinfo this way // ``is NOT RECOMMENDED, because the passing of authentication // information in clear text (such as URI) has proven to be a // security risk in almost every case where it has been used.'' -func EscapeUserinfo(user, password string) string { - raw := escape(user, encodeUserPassword) - if password != "" { - raw += ":" + escape(password, encodeUserPassword) +func UserPassword(username, password string) *Userinfo { + return &Userinfo{username, password, true} +} + +// The Userinfo type is an immutable encapsulation of username and +// password details for a URL. An existing Userinfo value is guaranteed +// to have a username set (potentially empty, as allowed by RFC 2396), +// and optionally a password. +type Userinfo struct { + username string + password string + passwordSet bool +} + +// Username returns the username. +func (u *Userinfo) Username() string { + return u.username +} + +// Password returns the password in case it is set, and whether it is set. +func (u *Userinfo) Password() (string, bool) { + if u.passwordSet { + return u.password, true } - return raw + return "", false } -// A URL represents a parsed URL (technically, a URI reference). -// The general form represented is: -// scheme://[userinfo@]host/path[?query][#fragment] -// The Raw, RawAuthority, RawPath, and RawQuery fields are in "wire format" -// (special characters must be hex-escaped if not meant to have special meaning). -// All other fields are logical values; '+' or '%' represent themselves. -// -// The various Raw values are supplied in wire format because -// clients typically have to split them into pieces before further -// decoding. -type URL struct { - Raw string // the original string - Scheme string // scheme - RawAuthority string // [userinfo@]host - RawUserinfo string // userinfo - Host string // host - RawPath string // /path[?query][#fragment] - Path string // /path - OpaquePath bool // path is opaque (unrooted when scheme is present) - RawQuery string // query - Fragment string // fragment +// String returns the encoded userinfo information in the standard form +// of "username[:password]". +func (u *Userinfo) String() string { + s := escape(u.username, encodeUserPassword) + if u.passwordSet { + s += ":" + escape(u.password, encodeUserPassword) + } + return s } // Maybe rawurl is of the form scheme:path. @@ -341,136 +342,112 @@ func ParseRequest(rawurl string) (url *URL, err error) { // in which case only absolute URLs or path-absolute relative URLs are allowed. // If viaRequest is false, all forms of relative URLs are allowed. func parse(rawurl string, viaRequest bool) (url *URL, err error) { - var ( - leadingSlash bool - path string - ) + var rest string if rawurl == "" { err = errors.New("empty url") goto Error } url = new(URL) - url.Raw = rawurl // Split off possible leading "http:", "mailto:", etc. // Cannot contain escaped characters. - if url.Scheme, path, err = getscheme(rawurl); err != nil { + if url.Scheme, rest, err = getscheme(rawurl); err != nil { goto Error } - leadingSlash = strings.HasPrefix(path, "/") - if url.Scheme != "" && !leadingSlash { - // RFC 2396: - // Absolute URI (has scheme) with non-rooted path - // is uninterpreted. It doesn't even have a ?query. - // This is the case that handles mailto:name@example.com. - url.RawPath = path + rest, url.RawQuery = split(rest, '?', true) - if url.Path, err = unescape(path, encodeOpaque); err != nil { - goto Error + if !strings.HasPrefix(rest, "/") { + if url.Scheme != "" { + // We consider rootless paths per RFC 3986 as opaque. + url.Opaque = rest + return url, nil } - url.OpaquePath = true - } else { - if viaRequest && !leadingSlash { + if viaRequest { err = errors.New("invalid URI for request") goto Error } + } - // Split off query before parsing path further. - url.RawPath = path - path, query := split(path, '?', false) - if len(query) > 1 { - url.RawQuery = query[1:] - } - - // Maybe path is //authority/path - if (url.Scheme != "" || !viaRequest) && - strings.HasPrefix(path, "//") && !strings.HasPrefix(path, "///") { - url.RawAuthority, path = split(path[2:], '/', false) - url.RawPath = url.RawPath[2+len(url.RawAuthority):] - } - - // Split authority into userinfo@host. - // If there's no @, split's default is wrong. Check explicitly. - var rawHost string - if strings.Index(url.RawAuthority, "@") < 0 { - rawHost = url.RawAuthority - } else { - url.RawUserinfo, rawHost = split(url.RawAuthority, '@', true) - } - - // We leave RawAuthority only in raw form because clients - // of common protocols should be using Userinfo and Host - // instead. Clients that wish to use RawAuthority will have to - // interpret it themselves: RFC 2396 does not define the meaning. - - if strings.Contains(rawHost, "%") { - // Host cannot contain escaped characters. - err = errors.New("hexadecimal escape in host") + if (url.Scheme != "" || !viaRequest) && strings.HasPrefix(rest, "//") && !strings.HasPrefix(rest, "///") { + var authority string + authority, rest = split(rest[2:], '/', false) + url.User, url.Host, err = parseAuthority(authority) + if err != nil { goto Error } - url.Host = rawHost - - if url.Path, err = unescape(path, encodePath); err != nil { + if strings.Contains(url.Host, "%") { + err = errors.New("hexadecimal escape in host") goto Error } } + if url.Path, err = unescape(rest, encodePath); err != nil { + goto Error + } return url, nil Error: return nil, &Error{"parse", rawurl, err} +} +func parseAuthority(authority string) (user *Userinfo, host string, err error) { + if strings.Index(authority, "@") < 0 { + host = authority + return + } + userinfo, host := split(authority, '@', true) + if strings.Index(userinfo, ":") < 0 { + if userinfo, err = unescape(userinfo, encodeUserPassword); err != nil { + return + } + user = User(userinfo) + } else { + username, password := split(userinfo, ':', true) + if username, err = unescape(username, encodeUserPassword); err != nil { + return + } + if password, err = unescape(password, encodeUserPassword); err != nil { + return + } + user = UserPassword(username, password) + } + return } // ParseWithReference is like Parse but allows a trailing #fragment. func ParseWithReference(rawurlref string) (url *URL, err error) { - // Cut off #frag. - rawurl, frag := split(rawurlref, '#', false) + // Cut off #frag + rawurl, frag := split(rawurlref, '#', true) if url, err = Parse(rawurl); err != nil { return nil, err } - url.Raw += frag - url.RawPath += frag - if len(frag) > 1 { - frag = frag[1:] - if url.Fragment, err = unescape(frag, encodeFragment); err != nil { - return nil, &Error{"parse", rawurl, err} - } + if frag == "" { + return url, nil + } + if url.Fragment, err = unescape(frag, encodeFragment); err != nil { + return nil, &Error{"parse", rawurlref, err} } return url, nil } // String reassembles url into a valid URL string. -// -// There are redundant fields stored in the URL structure: -// the String method consults Scheme, Path, Host, RawUserinfo, -// RawQuery, and Fragment, but not Raw, RawPath or RawAuthority. func (url *URL) String() string { + // TODO: Rewrite to use bytes.Buffer result := "" if url.Scheme != "" { result += url.Scheme + ":" } - if url.Host != "" || url.RawUserinfo != "" { - result += "//" - if url.RawUserinfo != "" { - // hide the password, if any - info := url.RawUserinfo - if i := strings.Index(info, ":"); i >= 0 { - info = info[0:i] + ":******" + if url.Opaque != "" { + result += url.Opaque + } else { + if url.Host != "" || url.User != nil { + result += "//" + if u := url.User; u != nil { + result += u.String() + "@" } - result += info + "@" - } - result += url.Host - } - if url.OpaquePath { - path := url.Path - if strings.HasPrefix(path, "/") { - result += "%2f" - path = path[1:] + result += url.Host } - result += escape(path, encodeOpaque) - } else { result += escape(url.Path, encodePath) } if url.RawQuery != "" { @@ -630,47 +607,38 @@ func (base *URL) Parse(ref string) (*URL, error) { // base or reference. If ref is an absolute URL, then ResolveReference // ignores base and returns a copy of ref. func (base *URL) ResolveReference(ref *URL) *URL { - url := new(URL) - switch { - case ref.IsAbs(): - *url = *ref - default: - // relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ] - *url = *base - if ref.RawAuthority != "" { - // The "net_path" case. - url.RawAuthority = ref.RawAuthority - url.Host = ref.Host - url.RawUserinfo = ref.RawUserinfo - } - switch { - case url.OpaquePath: - url.Path = ref.Path - url.RawPath = ref.RawPath - url.RawQuery = ref.RawQuery - case strings.HasPrefix(ref.Path, "/"): - // The "abs_path" case. - url.Path = ref.Path - url.RawPath = ref.RawPath - url.RawQuery = ref.RawQuery - default: - // The "rel_path" case. - path := resolvePath(base.Path, ref.Path) - if !strings.HasPrefix(path, "/") { - path = "/" + path - } - url.Path = path - url.RawPath = url.Path - url.RawQuery = ref.RawQuery - if ref.RawQuery != "" { - url.RawPath += "?" + url.RawQuery - } + if ref.IsAbs() { + url := *ref + return &url + } + // relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ] + url := *base + url.RawQuery = ref.RawQuery + url.Fragment = ref.Fragment + if ref.Opaque != "" { + url.Opaque = ref.Opaque + url.User = nil + url.Host = "" + url.Path = "" + return &url + } + if ref.Host != "" || ref.User != nil { + // The "net_path" case. + url.Host = ref.Host + url.User = ref.User + } + if strings.HasPrefix(ref.Path, "/") { + // The "abs_path" case. + url.Path = ref.Path + } else { + // The "rel_path" case. + path := resolvePath(base.Path, ref.Path) + if !strings.HasPrefix(path, "/") { + path = "/" + path } - - url.Fragment = ref.Fragment + url.Path = path } - url.Raw = url.String() - return url + return &url } // Query parses RawQuery and returns the corresponding values. @@ -679,7 +647,18 @@ func (u *URL) Query() Values { return v } -// EncodedPath returns the URL's path in "URL path encoded" form. -func (u *URL) EncodedPath() string { - return escape(u.Path, encodePath) +// RequestURI returns the encoded path?query or opaque?query +// string that would be used in an HTTP request for u. +func (u *URL) RequestURI() string { + result := u.Opaque + if result == "" { + result = escape(u.Path, encodePath) + if result == "" { + result = "/" + } + } + if u.RawQuery != "" { + result += "?" + u.RawQuery + } + return result } diff --git a/libgo/go/net/url/url_test.go b/libgo/go/net/url/url_test.go index dab3bfa..9fe5ff8 100644 --- a/libgo/go/net/url/url_test.go +++ b/libgo/go/net/url/url_test.go @@ -21,10 +21,8 @@ var urltests = []URLTest{ { "http://www.google.com", &URL{ - Raw: "http://www.google.com", - Scheme: "http", - RawAuthority: "www.google.com", - Host: "www.google.com", + Scheme: "http", + Host: "www.google.com", }, "", }, @@ -32,12 +30,9 @@ var urltests = []URLTest{ { "http://www.google.com/", &URL{ - Raw: "http://www.google.com/", - Scheme: "http", - RawAuthority: "www.google.com", - Host: "www.google.com", - RawPath: "/", - Path: "/", + Scheme: "http", + Host: "www.google.com", + Path: "/", }, "", }, @@ -45,12 +40,9 @@ var urltests = []URLTest{ { "http://www.google.com/file%20one%26two", &URL{ - Raw: "http://www.google.com/file%20one%26two", - Scheme: "http", - RawAuthority: "www.google.com", - Host: "www.google.com", - RawPath: "/file%20one%26two", - Path: "/file one&two", + Scheme: "http", + Host: "www.google.com", + Path: "/file one&two", }, "http://www.google.com/file%20one&two", }, @@ -58,13 +50,10 @@ var urltests = []URLTest{ { "ftp://webmaster@www.google.com/", &URL{ - Raw: "ftp://webmaster@www.google.com/", - Scheme: "ftp", - RawAuthority: "webmaster@www.google.com", - RawUserinfo: "webmaster", - Host: "www.google.com", - RawPath: "/", - Path: "/", + Scheme: "ftp", + User: User("webmaster"), + Host: "www.google.com", + Path: "/", }, "", }, @@ -72,13 +61,10 @@ var urltests = []URLTest{ { "ftp://john%20doe@www.google.com/", &URL{ - Raw: "ftp://john%20doe@www.google.com/", - Scheme: "ftp", - RawAuthority: "john%20doe@www.google.com", - RawUserinfo: "john%20doe", - Host: "www.google.com", - RawPath: "/", - Path: "/", + Scheme: "ftp", + User: User("john doe"), + Host: "www.google.com", + Path: "/", }, "ftp://john%20doe@www.google.com/", }, @@ -86,13 +72,10 @@ var urltests = []URLTest{ { "http://www.google.com/?q=go+language", &URL{ - Raw: "http://www.google.com/?q=go+language", - Scheme: "http", - RawAuthority: "www.google.com", - Host: "www.google.com", - RawPath: "/?q=go+language", - Path: "/", - RawQuery: "q=go+language", + Scheme: "http", + Host: "www.google.com", + Path: "/", + RawQuery: "q=go+language", }, "", }, @@ -100,13 +83,10 @@ var urltests = []URLTest{ { "http://www.google.com/?q=go%20language", &URL{ - Raw: "http://www.google.com/?q=go%20language", - Scheme: "http", - RawAuthority: "www.google.com", - Host: "www.google.com", - RawPath: "/?q=go%20language", - Path: "/", - RawQuery: "q=go%20language", + Scheme: "http", + Host: "www.google.com", + Path: "/", + RawQuery: "q=go%20language", }, "", }, @@ -114,48 +94,39 @@ var urltests = []URLTest{ { "http://www.google.com/a%20b?q=c+d", &URL{ - Raw: "http://www.google.com/a%20b?q=c+d", - Scheme: "http", - RawAuthority: "www.google.com", - Host: "www.google.com", - RawPath: "/a%20b?q=c+d", - Path: "/a b", - RawQuery: "q=c+d", + Scheme: "http", + Host: "www.google.com", + Path: "/a b", + RawQuery: "q=c+d", }, "", }, - // path without leading /, so no query parsing + // path without leading /, so no parsing { "http:www.google.com/?q=go+language", &URL{ - Raw: "http:www.google.com/?q=go+language", - Scheme: "http", - RawPath: "www.google.com/?q=go+language", - Path: "www.google.com/?q=go+language", - OpaquePath: true, + Scheme: "http", + Opaque: "www.google.com/", + RawQuery: "q=go+language", }, "http:www.google.com/?q=go+language", }, - // path without leading /, so no query parsing + // path without leading /, so no parsing { "http:%2f%2fwww.google.com/?q=go+language", &URL{ - Raw: "http:%2f%2fwww.google.com/?q=go+language", - Scheme: "http", - RawPath: "%2f%2fwww.google.com/?q=go+language", - Path: "//www.google.com/?q=go+language", - OpaquePath: true, + Scheme: "http", + Opaque: "%2f%2fwww.google.com/", + RawQuery: "q=go+language", }, - "http:%2f/www.google.com/?q=go+language", + "http:%2f%2fwww.google.com/?q=go+language", }, // non-authority { "mailto:/webmaster@golang.org", &URL{ - Raw: "mailto:/webmaster@golang.org", - Scheme: "mailto", - RawPath: "/webmaster@golang.org", - Path: "/webmaster@golang.org", + Scheme: "mailto", + Path: "/webmaster@golang.org", }, "", }, @@ -163,11 +134,8 @@ var urltests = []URLTest{ { "mailto:webmaster@golang.org", &URL{ - Raw: "mailto:webmaster@golang.org", - Scheme: "mailto", - RawPath: "webmaster@golang.org", - Path: "webmaster@golang.org", - OpaquePath: true, + Scheme: "mailto", + Opaque: "webmaster@golang.org", }, "", }, @@ -175,8 +143,6 @@ var urltests = []URLTest{ { "/foo?query=http://bad", &URL{ - Raw: "/foo?query=http://bad", - RawPath: "/foo?query=http://bad", Path: "/foo", RawQuery: "query=http://bad", }, @@ -186,12 +152,7 @@ var urltests = []URLTest{ { "//foo", &URL{ - RawAuthority: "foo", - Raw: "//foo", - Host: "foo", - Scheme: "", - RawPath: "", - Path: "", + Host: "foo", }, "", }, @@ -199,14 +160,10 @@ var urltests = []URLTest{ { "//user@foo/path?a=b", &URL{ - Raw: "//user@foo/path?a=b", - RawAuthority: "user@foo", - RawUserinfo: "user", - Scheme: "", - RawPath: "/path?a=b", - Path: "/path", - RawQuery: "a=b", - Host: "foo", + User: User("user"), + Host: "foo", + Path: "/path", + RawQuery: "a=b", }, "", }, @@ -218,36 +175,18 @@ var urltests = []URLTest{ { "///threeslashes", &URL{ - RawAuthority: "", - Raw: "///threeslashes", - Host: "", - Scheme: "", - RawPath: "///threeslashes", - Path: "///threeslashes", + Path: "///threeslashes", }, "", }, { "http://user:password@google.com", &URL{ - Raw: "http://user:password@google.com", - Scheme: "http", - RawAuthority: "user:password@google.com", - RawUserinfo: "user:password", - Host: "google.com", - }, - "http://user:******@google.com", - }, - { - "http://user:longerpass@google.com", - &URL{ - Raw: "http://user:longerpass@google.com", - Scheme: "http", - RawAuthority: "user:longerpass@google.com", - RawUserinfo: "user:longerpass", - Host: "google.com", + Scheme: "http", + User: UserPassword("user", "password"), + Host: "google.com", }, - "http://user:******@google.com", + "http://user:password@google.com", }, } @@ -255,13 +194,10 @@ var urlnofragtests = []URLTest{ { "http://www.google.com/?q=go+language#foo", &URL{ - Raw: "http://www.google.com/?q=go+language#foo", - Scheme: "http", - RawAuthority: "www.google.com", - Host: "www.google.com", - RawPath: "/?q=go+language#foo", - Path: "/", - RawQuery: "q=go+language#foo", + Scheme: "http", + Host: "www.google.com", + Path: "/", + RawQuery: "q=go+language#foo", }, "", }, @@ -271,28 +207,22 @@ var urlfragtests = []URLTest{ { "http://www.google.com/?q=go+language#foo", &URL{ - Raw: "http://www.google.com/?q=go+language#foo", - Scheme: "http", - RawAuthority: "www.google.com", - Host: "www.google.com", - RawPath: "/?q=go+language#foo", - Path: "/", - RawQuery: "q=go+language", - Fragment: "foo", + Scheme: "http", + Host: "www.google.com", + Path: "/", + RawQuery: "q=go+language", + Fragment: "foo", }, "", }, { "http://www.google.com/?q=go+language#foo%26bar", &URL{ - Raw: "http://www.google.com/?q=go+language#foo%26bar", - Scheme: "http", - RawAuthority: "www.google.com", - Host: "www.google.com", - RawPath: "/?q=go+language#foo%26bar", - Path: "/", - RawQuery: "q=go+language", - Fragment: "foo&bar", + Scheme: "http", + Host: "www.google.com", + Path: "/", + RawQuery: "q=go+language", + Fragment: "foo&bar", }, "http://www.google.com/?q=go+language#foo&bar", }, @@ -300,9 +230,15 @@ var urlfragtests = []URLTest{ // more useful string for debugging than fmt's struct printer func ufmt(u *URL) string { - return fmt.Sprintf("raw=%q, scheme=%q, rawpath=%q, auth=%q, userinfo=%q, host=%q, path=%q, rawq=%q, frag=%q", - u.Raw, u.Scheme, u.RawPath, u.RawAuthority, u.RawUserinfo, - u.Host, u.Path, u.RawQuery, u.Fragment) + var user, pass interface{} + if u.User != nil { + user = u.User.Username() + if p, ok := u.User.Password(); ok { + pass = p + } + } + return fmt.Sprintf("opaque=%q, scheme=%q, user=%#v, pass=%#v, host=%q, path=%q, rawq=%q, frag=%q", + u.Opaque, u.Scheme, user, pass, u.Host, u.Path, u.RawQuery, u.Fragment) } func DoTest(t *testing.T, parse func(string) (*URL, error), name string, tests []URLTest) { @@ -370,11 +306,11 @@ func DoTestString(t *testing.T, parse func(string) (*URL, error), name string, t t.Errorf("%s(%q) returned error %s", name, tt.in, err) continue } - s := u.String() expected := tt.in if len(tt.roundtrip) > 0 { expected = tt.roundtrip } + s := u.String() if s != expected { t.Errorf("%s(%q).String() == %q (expected %q)", name, tt.in, s, expected) } @@ -504,33 +440,11 @@ func TestEscape(t *testing.T) { } } -type UserinfoTest struct { - User string - Password string - Raw string -} - -var userinfoTests = []UserinfoTest{ - {"user", "password", "user:password"}, - {"foo:bar", "~!@#$%^&*()_+{}|[]\\-=`:;'\"<>?,./", - "foo%3Abar:~!%40%23$%25%5E&*()_+%7B%7D%7C%5B%5D%5C-=%60%3A;'%22%3C%3E?,.%2F"}, -} - -func TestEscapeUserinfo(t *testing.T) { - for _, tt := range userinfoTests { - if raw := EscapeUserinfo(tt.User, tt.Password); raw != tt.Raw { - t.Errorf("EscapeUserinfo(%q, %q) = %q, want %q", tt.User, tt.Password, raw, tt.Raw) - } - } -} - -func TestUnescapeUserinfo(t *testing.T) { - for _, tt := range userinfoTests { - if user, pass, err := UnescapeUserinfo(tt.Raw); user != tt.User || pass != tt.Password || err != nil { - t.Errorf("UnescapeUserinfo(%q) = %q, %q, %v, want %q, %q, nil", tt.Raw, user, pass, err, tt.User, tt.Password) - } - } -} +//var userinfoTests = []UserinfoTest{ +// {"user", "password", "user:password"}, +// {"foo:bar", "~!@#$%^&*()_+{}|[]\\-=`:;'\"<>?,./", +// "foo%3Abar:~!%40%23$%25%5E&*()_+%7B%7D%7C%5B%5D%5C-=%60%3A;'%22%3C%3E?,.%2F"}, +//} type EncodeQueryTest struct { m Values @@ -664,6 +578,57 @@ func TestResolveReference(t *testing.T) { t.Errorf("Expected an error from Parse wrapper parsing an empty string.") } + // Ensure Opaque resets the URL. + base = mustParse("scheme://user@foo.com/bar") + abs = base.ResolveReference(&URL{Opaque: "opaque"}) + want := mustParse("scheme:opaque") + if *abs != *want { + t.Errorf("ResolveReference failed to resolve opaque URL: want %#v, got %#v", abs, want) + } +} + +func TestResolveReferenceOpaque(t *testing.T) { + mustParse := func(url string) *URL { + u, err := ParseWithReference(url) + if err != nil { + t.Fatalf("Expected URL to parse: %q, got error: %v", url, err) + } + return u + } + for _, test := range resolveReferenceTests { + base := mustParse(test.base) + rel := mustParse(test.rel) + url := base.ResolveReference(rel) + urlStr := url.String() + if urlStr != test.expected { + t.Errorf("Resolving %q + %q != %q; got %q", test.base, test.rel, test.expected, urlStr) + } + } + + // Test that new instances are returned. + base := mustParse("http://foo.com/") + abs := base.ResolveReference(mustParse(".")) + if base == abs { + t.Errorf("Expected no-op reference to return new URL instance.") + } + barRef := mustParse("http://bar.com/") + abs = base.ResolveReference(barRef) + if abs == barRef { + t.Errorf("Expected resolution of absolute reference to return new URL instance.") + } + + // Test the convenience wrapper too + base = mustParse("http://foo.com/path/one/") + abs, _ = base.Parse("../two") + expected := "http://foo.com/path/two" + if abs.String() != expected { + t.Errorf("Parse wrapper got %q; expected %q", abs.String(), expected) + } + _, err := base.Parse("") + if err == nil { + t.Errorf("Expected an error from Parse wrapper parsing an empty string.") + } + } func TestQueryValues(t *testing.T) { @@ -747,3 +712,60 @@ func TestParseQuery(t *testing.T) { } } } + +type RequestURITest struct { + url *URL + out string +} + +var requritests = []RequestURITest{ + { + &URL{ + Scheme: "http", + Host: "example.com", + Path: "", + }, + "/", + }, + { + &URL{ + Scheme: "http", + Host: "example.com", + Path: "/a b", + }, + "/a%20b", + }, + { + &URL{ + Scheme: "http", + Host: "example.com", + Path: "/a b", + RawQuery: "q=go+language", + }, + "/a%20b?q=go+language", + }, + { + &URL{ + Scheme: "myschema", + Opaque: "opaque", + }, + "opaque", + }, + { + &URL{ + Scheme: "myschema", + Opaque: "opaque", + RawQuery: "q=go+language", + }, + "opaque?q=go+language", + }, +} + +func TestRequestURI(t *testing.T) { + for _, tt := range requritests { + s := tt.url.RequestURI() + if s != tt.out { + t.Errorf("%#v.RequestURI() == %q (expected %q)", tt.url, s, tt.out) + } + } +} diff --git a/libgo/go/old/netchan/common.go b/libgo/go/old/netchan/common.go index 710b63a..d0daf53 100644 --- a/libgo/go/old/netchan/common.go +++ b/libgo/go/old/netchan/common.go @@ -165,9 +165,11 @@ func (cs *clientSet) sync(timeout time.Duration) error { deadline := time.Now().Add(timeout) // seq remembers the clients and their seqNum at point of entry. seq := make(map[unackedCounter]int64) + cs.mu.Lock() for client := range cs.clients { seq[client] = client.seq() } + cs.mu.Unlock() for { pending := false cs.mu.Lock() diff --git a/libgo/go/old/regexp/regexp.go b/libgo/go/old/regexp/regexp.go index 86df4de..d3044d0 100644 --- a/libgo/go/old/regexp/regexp.go +++ b/libgo/go/old/regexp/regexp.go @@ -1,3 +1,4 @@ +// Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. diff --git a/libgo/go/os/dir.go b/libgo/go/os/dir.go index 53a84b1..0e3c399 100644 --- a/libgo/go/os/dir.go +++ b/libgo/go/os/dir.go @@ -28,19 +28,7 @@ func clen(n []byte) int { var elen int; -// Readdirnames reads and returns a slice of names from the directory f. -// -// If n > 0, Readdirnames returns at most n names. In this case, if -// Readdirnames returns an empty slice, it will return a non-nil error -// explaining why. At the end of a directory, the error is os.EOF. -// -// If n <= 0, Readdirnames returns all the names from the directory in -// a single slice. In this case, if Readdirnames succeeds (reads all -// the way to the end of the directory), it returns the slice and a -// nil error. If it encounters an error before the end of the -// directory, Readdirnames returns the names read until that point and -// a non-nil error. -func (file *File) Readdirnames(n int) (names []string, err error) { +func (file *File) readdirnames(n int) (names []string, err error) { if elen == 0 { var dummy syscall.Dirent; elen = (unsafe.Offsetof(dummy.Name) + diff --git a/libgo/go/os/dir_plan9.go b/libgo/go/os/dir_plan9.go index 7822820..f2dc154 100644 --- a/libgo/go/os/dir_plan9.go +++ b/libgo/go/os/dir_plan9.go @@ -10,22 +10,7 @@ import ( "syscall" ) -// Readdir reads the contents of the directory associated with file and -// returns an array of up to n FileInfo structures, as would be returned -// by Lstat, in directory order. Subsequent calls on the same file will yield -// further FileInfos. -// -// If n > 0, Readdir returns at most n FileInfo structures. In this case, if -// Readdirnames returns an empty slice, it will return a non-nil error -// explaining why. At the end of a directory, the error is io.EOF. -// -// If n <= 0, Readdir returns all the FileInfo from the directory in -// a single slice. In this case, if Readdir succeeds (reads all -// the way to the end of the directory), it returns the slice and a -// nil error. If it encounters an error before the end of the -// directory, Readdir returns the FileInfo read until that point -// and a non-nil error. -func (file *File) Readdir(n int) (fi []FileInfo, err error) { +func (file *File) readdir(n int) (fi []FileInfo, err error) { // If this file has no dirinfo, create one. if file.dirinfo == nil { file.dirinfo = new(dirInfo) @@ -76,19 +61,7 @@ func (file *File) Readdir(n int) (fi []FileInfo, err error) { return result, nil } -// Readdirnames reads and returns a slice of names from the directory f. -// -// If n > 0, Readdirnames returns at most n names. In this case, if -// Readdirnames returns an empty slice, it will return a non-nil error -// explaining why. At the end of a directory, the error is io.EOF. -// -// If n <= 0, Readdirnames returns all the names from the directory in -// a single slice. In this case, if Readdirnames succeeds (reads all -// the way to the end of the directory), it returns the slice and a -// nil error. If it encounters an error before the end of the -// directory, Readdirnames returns the names read until that point and -// a non-nil error. -func (file *File) Readdirnames(n int) (names []string, err error) { +func (file *File) readdirnames(n int) (names []string, err error) { fi, err := file.Readdir(n) names = make([]string, len(fi)) for i := range fi { diff --git a/libgo/go/os/dir_unix.go b/libgo/go/os/dir_unix.go index e7a2955..f41f939 100644 --- a/libgo/go/os/dir_unix.go +++ b/libgo/go/os/dir_unix.go @@ -15,19 +15,7 @@ const ( blockSize = 4096 ) -// Readdirnames reads and returns a slice of names from the directory f. -// -// If n > 0, Readdirnames returns at most n names. In this case, if -// Readdirnames returns an empty slice, it will return a non-nil error -// explaining why. At the end of a directory, the error is io.EOF. -// -// If n <= 0, Readdirnames returns all the names from the directory in -// a single slice. In this case, if Readdirnames succeeds (reads all -// the way to the end of the directory), it returns the slice and a -// nil error. If it encounters an error before the end of the -// directory, Readdirnames returns the names read until that point and -// a non-nil error. -func (f *File) Readdirnames(n int) (names []string, err error) { +func (f *File) readdirnames(n int) (names []string, err error) { // If this file has no dirinfo, create one. if f.dirinfo == nil { f.dirinfo = new(dirInfo) diff --git a/libgo/go/os/doc.go b/libgo/go/os/doc.go new file mode 100644 index 0000000..ef857c0 --- /dev/null +++ b/libgo/go/os/doc.go @@ -0,0 +1,52 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package os + +// FindProcess looks for a running process by its pid. +// The Process it returns can be used to obtain information +// about the underlying operating system process. +func FindProcess(pid int) (p *Process, err error) { + return findProcess(pid) +} + +// Hostname returns the host name reported by the kernel. +func Hostname() (name string, err error) { + return hostname() +} + +// Readdir reads the contents of the directory associated with file and +// returns an array of up to n FileInfo values, as would be returned +// by Lstat, in directory order. Subsequent calls on the same file will yield +// further FileInfos. +// +// If n > 0, Readdir returns at most n FileInfo structures. In this case, if +// Readdir returns an empty slice, it will return a non-nil error +// explaining why. At the end of a directory, the error is io.EOF. +// +// If n <= 0, Readdir returns all the FileInfo from the directory in +// a single slice. In this case, if Readdir succeeds (reads all +// the way to the end of the directory), it returns the slice and a +// nil error. If it encounters an error before the end of the +// directory, Readdir returns the FileInfo read until that point +// and a non-nil error. +func (f *File) Readdir(n int) (fi []FileInfo, err error) { + return f.readdir(n) +} + +// Readdirnames reads and returns a slice of names from the directory f. +// +// If n > 0, Readdirnames returns at most n names. In this case, if +// Readdirnames returns an empty slice, it will return a non-nil error +// explaining why. At the end of a directory, the error is io.EOF. +// +// If n <= 0, Readdirnames returns all the names from the directory in +// a single slice. In this case, if Readdirnames succeeds (reads all +// the way to the end of the directory), it returns the slice and a +// nil error. If it encounters an error before the end of the +// directory, Readdirnames returns the names read until that point and +// a non-nil error. +func (f *File) Readdirnames(n int) (names []string, err error) { + return f.readdirnames(n) +} diff --git a/libgo/go/os/error_plan9.go b/libgo/go/os/error_plan9.go index 8f005ef..3c727b2 100644 --- a/libgo/go/os/error_plan9.go +++ b/libgo/go/os/error_plan9.go @@ -17,10 +17,6 @@ type SyscallError struct { func (e *SyscallError) Error() string { return e.Syscall + ": " + e.Err } -// Note: If the name of the function NewSyscallError changes, -// pkg/go/doc/doc.go should be adjusted since it hardwires -// this name in a heuristic. - // NewSyscallError returns, as an error, a new SyscallError // with the given system call name and error details. // As a convenience, if err is nil, NewSyscallError returns nil. diff --git a/libgo/go/os/error_posix.go b/libgo/go/os/error_posix.go index ebbe436..1a08627 100644 --- a/libgo/go/os/error_posix.go +++ b/libgo/go/os/error_posix.go @@ -59,10 +59,6 @@ type SyscallError struct { func (e *SyscallError) Error() string { return e.Syscall + ": " + e.Errno.Error() } -// Note: If the name of the function NewSyscallError changes, -// pkg/go/doc/doc.go should be adjusted since it hardwires -// this name in a heuristic. - // NewSyscallError returns, as an error, a new SyscallError // with the given system call name and error details. // As a convenience, if err is nil, NewSyscallError returns nil. diff --git a/libgo/go/os/exec/lp_unix.go b/libgo/go/os/exec/lp_unix.go index a221137..2d3a919 100644 --- a/libgo/go/os/exec/lp_unix.go +++ b/libgo/go/os/exec/lp_unix.go @@ -47,8 +47,9 @@ func LookPath(file string) (string, error) { // Unix shell semantics: path element "" means "." dir = "." } - if err := findExecutable(dir + "/" + file); err == nil { - return dir + "/" + file, nil + path := dir + "/" + file + if err := findExecutable(path); err == nil { + return path, nil } } return "", &Error{file, ErrNotFound} diff --git a/libgo/go/os/exec/lp_windows.go b/libgo/go/os/exec/lp_windows.go index d09e839..b7efcd6 100644 --- a/libgo/go/os/exec/lp_windows.go +++ b/libgo/go/os/exec/lp_windows.go @@ -42,6 +42,11 @@ func findExecutable(file string, exts []string) (string, error) { return ``, os.ENOENT } +// LookPath searches for an executable binary named file +// in the directories named by the PATH environment variable. +// If file contains a slash, it is tried directly and the PATH is not consulted. +// LookPath also uses PATHEXT environment variable to match +// a suitable candidate. func LookPath(file string) (f string, err error) { x := os.Getenv(`PATHEXT`) if x == `` { diff --git a/libgo/go/os/exec_plan9.go b/libgo/go/os/exec_plan9.go index 9a0db6d..879d4d2 100644 --- a/libgo/go/os/exec_plan9.go +++ b/libgo/go/os/exec_plan9.go @@ -138,10 +138,7 @@ func (p *Process) Release() error { return nil } -// FindProcess looks for a running process by its pid. -// The Process it returns can be used to obtain information -// about the underlying operating system process. -func FindProcess(pid int) (p *Process, err error) { +func findProcess(pid int) (p *Process, err error) { // NOOP for Plan 9. return newProcess(pid, 0), nil } diff --git a/libgo/go/os/exec_unix.go b/libgo/go/os/exec_unix.go index 3758138..6c11b63 100644 --- a/libgo/go/os/exec_unix.go +++ b/libgo/go/os/exec_unix.go @@ -72,10 +72,7 @@ func (p *Process) Release() error { return nil } -// FindProcess looks for a running process by its pid. -// The Process it returns can be used to obtain information -// about the underlying operating system process. -func FindProcess(pid int) (p *Process, err error) { +func findProcess(pid int) (p *Process, err error) { // NOOP for unix. return newProcess(pid, 0), nil } diff --git a/libgo/go/os/exec_windows.go b/libgo/go/os/exec_windows.go index c4c9dcf..7eb7d19 100644 --- a/libgo/go/os/exec_windows.go +++ b/libgo/go/os/exec_windows.go @@ -11,6 +11,8 @@ import ( "unsafe" ) +// Wait waits for the Process to exit or stop, and then returns a +// Waitmsg describing its status and an error, if any. func (p *Process) Wait(options int) (w *Waitmsg, err error) { s, e := syscall.WaitForSingleObject(syscall.Handle(p.handle), syscall.INFINITE) switch s { @@ -43,6 +45,7 @@ func (p *Process) Signal(sig Signal) error { return syscall.Errno(syscall.EWINDOWS) } +// Release releases any resources associated with the Process. func (p *Process) Release() error { if p.handle == -1 { return EINVAL @@ -57,7 +60,7 @@ func (p *Process) Release() error { return nil } -func FindProcess(pid int) (p *Process, err error) { +func findProcess(pid int) (p *Process, err error) { const da = syscall.STANDARD_RIGHTS_READ | syscall.PROCESS_QUERY_INFORMATION | syscall.SYNCHRONIZE h, e := syscall.OpenProcess(da, false, uint32(pid)) diff --git a/libgo/go/os/file.go b/libgo/go/os/file.go index 71845d3..3efa650 100644 --- a/libgo/go/os/file.go +++ b/libgo/go/os/file.go @@ -158,8 +158,8 @@ func (f *File) WriteString(s string) (ret int, err error) { // Mkdir creates a new directory with the specified name and permission bits. // It returns an error, if any. -func Mkdir(name string, perm uint32) error { - e := syscall.Mkdir(name, perm) +func Mkdir(name string, perm FileMode) error { + e := syscall.Mkdir(name, syscallMode(perm)) if e != nil { return &PathError{"mkdir", name, e} } diff --git a/libgo/go/os/file_posix.go b/libgo/go/os/file_posix.go index 8231ef4..86ac1ca 100644 --- a/libgo/go/os/file_posix.go +++ b/libgo/go/os/file_posix.go @@ -81,18 +81,34 @@ func Rename(oldname, newname string) error { return nil } +// syscallMode returns the syscall-specific mode bits from Go's portable mode bits. +func syscallMode(i FileMode) (o uint32) { + o |= uint32(i.Perm()) + if i&ModeSetuid != 0 { + o |= syscall.S_ISUID + } + if i&ModeSetgid != 0 { + o |= syscall.S_ISGID + } + if i&ModeSticky != 0 { + o |= syscall.S_ISVTX + } + // No mapping for Go's ModeTemporary (plan9 only). + return +} + // Chmod changes the mode of the named file to mode. // If the file is a symbolic link, it changes the mode of the link's target. -func Chmod(name string, mode uint32) error { - if e := syscall.Chmod(name, mode); e != nil { +func Chmod(name string, mode FileMode) error { + if e := syscall.Chmod(name, syscallMode(mode)); e != nil { return &PathError{"chmod", name, e} } return nil } // Chmod changes the mode of the file to mode. -func (f *File) Chmod(mode uint32) error { - if e := syscall.Fchmod(f.fd, mode); e != nil { +func (f *File) Chmod(mode FileMode) error { + if e := syscall.Fchmod(f.fd, syscallMode(mode)); e != nil { return &PathError{"chmod", f.name, e} } return nil diff --git a/libgo/go/os/file_unix.go b/libgo/go/os/file_unix.go index 069baa1..9a9ed92 100644 --- a/libgo/go/os/file_unix.go +++ b/libgo/go/os/file_unix.go @@ -60,8 +60,8 @@ const DevNull = "/dev/null" // (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful, // methods on the returned File can be used for I/O. // It returns the File and an error, if any. -func OpenFile(name string, flag int, perm uint32) (file *File, err error) { - r, e := syscall.Open(name, flag|syscall.O_CLOEXEC, perm) +func OpenFile(name string, flag int, perm FileMode) (file *File, err error) { + r, e := syscall.Open(name, flag|syscall.O_CLOEXEC, syscallMode(perm)) if e != nil { return nil, &PathError{"open", name, e} } @@ -145,22 +145,7 @@ func Lstat(name string) (fi FileInfo, err error) { return fileInfoFromStat(&stat, name), nil } -// Readdir reads the contents of the directory associated with file and -// returns an array of up to n FileInfo values, as would be returned -// by Lstat, in directory order. Subsequent calls on the same file will yield -// further FileInfos. -// -// If n > 0, Readdir returns at most n FileInfo structures. In this case, if -// Readdir returns an empty slice, it will return a non-nil error -// explaining why. At the end of a directory, the error is io.EOF. -// -// If n <= 0, Readdir returns all the FileInfo from the directory in -// a single slice. In this case, if Readdir succeeds (reads all -// the way to the end of the directory), it returns the slice and a -// nil error. If it encounters an error before the end of the -// directory, Readdir returns the FileInfo read until that point -// and a non-nil error. -func (f *File) Readdir(n int) (fi []FileInfo, err error) { +func (f *File) readdir(n int) (fi []FileInfo, err error) { dirname := f.name if dirname == "" { dirname = "." diff --git a/libgo/go/os/path.go b/libgo/go/os/path.go index bc14a78..e962f3e 100644 --- a/libgo/go/os/path.go +++ b/libgo/go/os/path.go @@ -13,7 +13,7 @@ import "io" // directories that MkdirAll creates. // If path is already a directory, MkdirAll does nothing // and returns nil. -func MkdirAll(path string, perm uint32) error { +func MkdirAll(path string, perm FileMode) error { // If path exists, stop with success or error. dir, err := Stat(path) if err == nil { diff --git a/libgo/go/os/stat_openbsd.go b/libgo/go/os/stat_openbsd.go index b0a569e..8d1323a 100644 --- a/libgo/go/os/stat_openbsd.go +++ b/libgo/go/os/stat_openbsd.go @@ -45,6 +45,9 @@ func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo { if st.Mode&syscall.S_ISUID != 0 { fs.mode |= ModeSetuid } + if st.Mode&syscall.S_ISVTX != 0 { + fs.mode |= ModeSticky + } return fs } diff --git a/libgo/go/os/sys_bsd.go b/libgo/go/os/sys_bsd.go index d196469..0f263f1 100644 --- a/libgo/go/os/sys_bsd.go +++ b/libgo/go/os/sys_bsd.go @@ -11,7 +11,7 @@ package os import "syscall" -func Hostname() (name string, err error) { +func hostname() (name string, err error) { name, err = syscall.Sysctl("kern.hostname") if err != nil { return "", NewSyscallError("sysctl kern.hostname", err) diff --git a/libgo/go/os/sys_linux.go b/libgo/go/os/sys_linux.go index d322a63..76cdf50 100644 --- a/libgo/go/os/sys_linux.go +++ b/libgo/go/os/sys_linux.go @@ -6,8 +6,7 @@ package os -// Hostname returns the host name reported by the kernel. -func Hostname() (name string, err error) { +func hostname() (name string, err error) { f, err := Open("/proc/sys/kernel/hostname") if err != nil { return "", err diff --git a/libgo/go/os/sys_plan9.go b/libgo/go/os/sys_plan9.go index 8ad89fb..07a7905 100644 --- a/libgo/go/os/sys_plan9.go +++ b/libgo/go/os/sys_plan9.go @@ -6,7 +6,7 @@ package os -func Hostname() (name string, err error) { +func hostname() (name string, err error) { f, err := Open("#c/sysname") if err != nil { return "", err diff --git a/libgo/go/os/types.go b/libgo/go/os/types.go index bf00980..a3f187c 100644 --- a/libgo/go/os/types.go +++ b/libgo/go/os/types.go @@ -39,7 +39,7 @@ const ( ModeDir FileMode = 1 << (32 - 1 - iota) // d: is a directory ModeAppend // a: append-only ModeExclusive // l: exclusive use - ModeTemporary // t: temporary file (not backed up) + ModeTemporary // T: temporary file (not backed up) ModeSymlink // L: symbolic link ModeDevice // D: device file ModeNamedPipe // p: named pipe (FIFO) @@ -47,6 +47,7 @@ const ( ModeSetuid // u: setuid ModeSetgid // g: setgid ModeCharDevice // c: Unix character device, when ModeDevice is set + ModeSticky // t: sticky // Mask for the type bits. For regular files, none will be set. ModeType = ModeDir | ModeSymlink | ModeNamedPipe | ModeSocket | ModeDevice @@ -55,7 +56,7 @@ const ( ) func (m FileMode) String() string { - const str = "daltLDpSugc" + const str = "dalTLDpSugct" var buf [20]byte w := 0 for i, c := range str { diff --git a/libgo/go/patch/textdiff.go b/libgo/go/patch/textdiff.go index adb629a..c9cffee 100644 --- a/libgo/go/patch/textdiff.go +++ b/libgo/go/patch/textdiff.go @@ -1,3 +1,7 @@ +// 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 patch import ( diff --git a/libgo/go/path/example_test.go b/libgo/go/path/example_test.go new file mode 100644 index 0000000..f0ac130 --- /dev/null +++ b/libgo/go/path/example_test.go @@ -0,0 +1,65 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package path + +/* Commented out until gccgo has example support. + +import ( + "fmt" + "path" +) + +// b +func ExampleBase() { + fmt.Println(path.Base("/a/b")) +} + +// Clean("a/c") = "a/c" +// Clean("a//c") = "a/c" +// Clean("a/c/.") = "a/c" +// Clean("a/c/b/..") = "a/c" +// Clean("/../a/c") = "/a/c" +// Clean("/../a/b/../././/c") = "/a/c" +func ExampleClean() { + paths := []string{ + "a/c", + "a//c", + "a/c/.", + "a/c/b/..", + "/../a/c", + "/../a/b/../././/c", + } + + for _, p := range paths { + fmt.Printf("Clean(%q) = %q\n", p, path.Clean(p)) + } +} + +// /a/b +func ExampleDir() { + fmt.Println(path.Dir("/a/b/c")) +} + +// .css +func ExampleExt() { + fmt.Println(path.Ext("/a/b/c/bar.css")) +} + +// true +func ExampleIsAbs() { + fmt.Println(path.IsAbs("/dev/null")) +} + +// a/b/c +func ExampleJoin() { + fmt.Println(path.Join("a", "b", "c")) +} + +// static/ myfile.css +func ExampleSplit() { + fmt.Println(path.Split("static/myfile.css")) +} + +*/ diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go index 8e28a53..902a359 100644 --- a/libgo/go/reflect/all_test.go +++ b/libgo/go/reflect/all_test.go @@ -1364,8 +1364,19 @@ func TestFieldByName(t *testing.T) { } func TestImportPath(t *testing.T) { - if path := TypeOf(&base64.Encoding{}).Elem().PkgPath(); path != "libgo_encoding.base64" { - t.Errorf(`TypeOf(&base64.Encoding{}).Elem().PkgPath() = %q, want "libgo_encoding.base64"`, path) + tests := []struct { + t Type + path string + }{ + {TypeOf(&base64.Encoding{}).Elem(), "libgo_encoding.base64"}, + {TypeOf(uint(0)), ""}, + {TypeOf(map[string]int{}), ""}, + {TypeOf((*error)(nil)).Elem(), ""}, + } + for _, test := range tests { + if path := test.t.PkgPath(); path != test.path { + t.Errorf("%v.PkgPath() = %q, want %q", test.t, path, test.path) + } } } diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go index a3c5658..e30cf08 100644 --- a/libgo/go/reflect/type.go +++ b/libgo/go/reflect/type.go @@ -69,7 +69,7 @@ type Type interface { // PkgPath returns the type's package path. // The package path is a full package import path like "encoding/base64". - // PkgPath returns an empty string for unnamed types. + // PkgPath returns an empty string for unnamed or predeclared types. PkgPath() string // Size returns the number of bytes needed to store diff --git a/libgo/go/regexp/all_test.go b/libgo/go/regexp/all_test.go index e729510..107dfe3 100644 --- a/libgo/go/regexp/all_test.go +++ b/libgo/go/regexp/all_test.go @@ -289,30 +289,45 @@ func TestLiteralPrefix(t *testing.T) { } } -type numSubexpCase struct { - input string - expected int -} - -var numSubexpCases = []numSubexpCase{ - {``, 0}, - {`.*`, 0}, - {`abba`, 0}, - {`ab(b)a`, 1}, - {`ab(.*)a`, 1}, - {`(.*)ab(.*)a`, 2}, - {`(.*)(ab)(.*)a`, 3}, - {`(.*)((a)b)(.*)a`, 4}, - {`(.*)(\(ab)(.*)a`, 3}, - {`(.*)(\(a\)b)(.*)a`, 3}, -} - -func TestNumSubexp(t *testing.T) { - for _, c := range numSubexpCases { +type subexpCase struct { + input string + num int + names []string +} + +var subexpCases = []subexpCase{ + {``, 0, nil}, + {`.*`, 0, nil}, + {`abba`, 0, nil}, + {`ab(b)a`, 1, []string{"", ""}}, + {`ab(.*)a`, 1, []string{"", ""}}, + {`(.*)ab(.*)a`, 2, []string{"", "", ""}}, + {`(.*)(ab)(.*)a`, 3, []string{"", "", "", ""}}, + {`(.*)((a)b)(.*)a`, 4, []string{"", "", "", "", ""}}, + {`(.*)(\(ab)(.*)a`, 3, []string{"", "", "", ""}}, + {`(.*)(\(a\)b)(.*)a`, 3, []string{"", "", "", ""}}, + {`(?P.*)(?P(a)b)(?P.*)a`, 4, []string{"", "foo", "bar", "", "foo"}}, +} + +func TestSubexp(t *testing.T) { + for _, c := range subexpCases { re := MustCompile(c.input) n := re.NumSubexp() - if n != c.expected { - t.Errorf("NumSubexp for %q returned %d, expected %d", c.input, n, c.expected) + if n != c.num { + t.Errorf("%q: NumSubexp = %d, want %d", c.input, n, c.num) + continue + } + names := re.SubexpNames() + if len(names) != 1+n { + t.Errorf("%q: len(SubexpNames) = %d, want %d", c.input, len(names), n) + continue + } + if c.names != nil { + for i := 0; i < 1+n; i++ { + if names[i] != c.names[i] { + t.Errorf("%q: SubexpNames[%d] = %q, want %q", c.input, i, names[i], c.names[i]) + } + } } } } diff --git a/libgo/go/regexp/exec.go b/libgo/go/regexp/exec.go index e16a1b5..333ca25 100644 --- a/libgo/go/regexp/exec.go +++ b/libgo/go/regexp/exec.go @@ -1,3 +1,7 @@ +// 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 regexp import ( diff --git a/libgo/go/regexp/regexp.go b/libgo/go/regexp/regexp.go index b0c6a0b..ef94fa0 100644 --- a/libgo/go/regexp/regexp.go +++ b/libgo/go/regexp/regexp.go @@ -1,3 +1,4 @@ +// 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. @@ -85,6 +86,7 @@ type Regexp struct { prefixRune rune // first rune in prefix cond syntax.EmptyOp // empty-width conditions required at start of match numSubexp int + subexpNames []string longest bool // cache of machines for running regexp @@ -140,17 +142,20 @@ func compile(expr string, mode syntax.Flags, longest bool) (*Regexp, error) { return nil, err } maxCap := re.MaxCap() + capNames := re.CapNames() + re = re.Simplify() prog, err := syntax.Compile(re) if err != nil { return nil, err } regexp := &Regexp{ - expr: expr, - prog: prog, - numSubexp: maxCap, - cond: prog.StartCond(), - longest: longest, + expr: expr, + prog: prog, + numSubexp: maxCap, + subexpNames: capNames, + cond: prog.StartCond(), + longest: longest, } regexp.prefix, regexp.prefixComplete = prog.Prefix() if regexp.prefix != "" { @@ -223,6 +228,15 @@ func (re *Regexp) NumSubexp() int { return re.numSubexp } +// SubexpNames returns the names of the parenthesized subexpressions +// in this Regexp. The name for the first sub-expression is names[1], +// so that if m is a match slice, the name for m[i] is SubexpNames()[i]. +// Since the Regexp as a whole cannot be named, names[0] is always +// the empty string. The slice should not be modified. +func (re *Regexp) SubexpNames() []string { + return re.subexpNames +} + const endOfText rune = -1 // input abstracts different representations of the input text. It provides diff --git a/libgo/go/regexp/syntax/compile.go b/libgo/go/regexp/syntax/compile.go index 21c6565..41955bf 100644 --- a/libgo/go/regexp/syntax/compile.go +++ b/libgo/go/regexp/syntax/compile.go @@ -1,3 +1,7 @@ +// 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 syntax import "unicode" diff --git a/libgo/go/regexp/syntax/prog.go b/libgo/go/regexp/syntax/prog.go index 84ebb83..902d3b3 100644 --- a/libgo/go/regexp/syntax/prog.go +++ b/libgo/go/regexp/syntax/prog.go @@ -1,3 +1,7 @@ +// 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 syntax import ( diff --git a/libgo/go/regexp/syntax/prog_test.go b/libgo/go/regexp/syntax/prog_test.go index 70959f6..0d96507 100644 --- a/libgo/go/regexp/syntax/prog_test.go +++ b/libgo/go/regexp/syntax/prog_test.go @@ -1,3 +1,7 @@ +// 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 syntax_test import ( diff --git a/libgo/go/regexp/syntax/regexp.go b/libgo/go/regexp/syntax/regexp.go index adcfe29..668a077 100644 --- a/libgo/go/regexp/syntax/regexp.go +++ b/libgo/go/regexp/syntax/regexp.go @@ -303,3 +303,19 @@ func (re *Regexp) MaxCap() int { } return m } + +// CapNames walks the regexp to find the names of capturing groups. +func (re *Regexp) CapNames() []string { + names := make([]string, re.MaxCap()+1) + re.capNames(names) + return names +} + +func (re *Regexp) capNames(names []string) { + if re.Op == OpCapture { + names[re.Cap] = re.Name + } + for _, sub := range re.Sub { + sub.capNames(names) + } +} diff --git a/libgo/go/runtime/extern.go b/libgo/go/runtime/extern.go index 25c7470..88598cb 100644 --- a/libgo/go/runtime/extern.go +++ b/libgo/go/runtime/extern.go @@ -27,7 +27,7 @@ func Caller(skip int) (pc uintptr, file string, line int, ok bool) // Callers fills the slice pc with the program counters of function invocations // on the calling goroutine's stack. The argument skip is the number of stack frames -// to skip before recording in pc, with 0 starting at the caller of Caller. +// to skip before recording in pc, with 0 starting at the caller of Callers. // It returns the number of entries written to pc. func Callers(skip int, pc []uintptr) int diff --git a/libgo/go/runtime/gc_test.go b/libgo/go/runtime/gc_test.go index 63c6037..00b3a04 100644 --- a/libgo/go/runtime/gc_test.go +++ b/libgo/go/runtime/gc_test.go @@ -1,3 +1,7 @@ +// 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 runtime_test import ( diff --git a/libgo/go/sync/atomic/atomic_test.go b/libgo/go/sync/atomic/atomic_test.go index 02ee24b..ad75576 100644 --- a/libgo/go/sync/atomic/atomic_test.go +++ b/libgo/go/sync/atomic/atomic_test.go @@ -1037,7 +1037,7 @@ func TestStoreLoadSeqCst32(t *testing.T) { if my != i && his != i { t.Fatalf("store/load are not sequentially consistent: %d/%d (%d)", my, his, i) } - ack[me][(i-1)%3] = -1 + StoreInt32(&ack[me][(i-1)%3], -1) } c <- true }(p) @@ -1078,7 +1078,7 @@ func TestStoreLoadSeqCst64(t *testing.T) { if my != i && his != i { t.Fatalf("store/load are not sequentially consistent: %d/%d (%d)", my, his, i) } - ack[me][(i-1)%3] = -1 + StoreInt64(&ack[me][(i-1)%3], -1) } c <- true }(p) diff --git a/libgo/go/syscall/syscall.go b/libgo/go/syscall/syscall.go index ad9df6c..f777197 100644 --- a/libgo/go/syscall/syscall.go +++ b/libgo/go/syscall/syscall.go @@ -34,3 +34,11 @@ var _zero uintptr var dummy *byte const sizeofPtr uintptr = uintptr(unsafe.Sizeof(dummy)) + +func (ts *Timespec) Unix() (sec int64, nsec int64) { + return int64(ts.Sec), int64(ts.Nsec) +} + +func (tv *Timeval) Unix() (sec int64, nsec int64) { + return int64(tv.Sec), int64(tv.Usec) * 1000 +} diff --git a/libgo/go/testing/example.go b/libgo/go/testing/example.go index fdeda13..7f8ff2d 100644 --- a/libgo/go/testing/example.go +++ b/libgo/go/testing/example.go @@ -25,13 +25,6 @@ func RunExamples(examples []InternalExample) (ok bool) { var eg InternalExample stdout, stderr := os.Stdout, os.Stderr - defer func() { - os.Stdout, os.Stderr = stdout, stderr - if e := recover(); e != nil { - fmt.Printf("--- FAIL: %s\npanic: %v\n", eg.Name, e) - os.Exit(1) - } - }() for _, eg = range examples { if *chatty { diff --git a/libgo/go/testing/testing.go b/libgo/go/testing/testing.go index cfe212d..f1acb97 100644 --- a/libgo/go/testing/testing.go +++ b/libgo/go/testing/testing.go @@ -3,7 +3,7 @@ // license that can be found in the LICENSE file. // Package testing provides support for automated testing of Go packages. -// It is intended to be used in concert with the ``gotest'' utility, which automates +// It is intended to be used in concert with the ``go test'' command, which automates // execution of any function of the form // func TestXxx(*testing.T) // where Xxx can be any alphanumeric string (but the first letter must not be in @@ -21,6 +21,7 @@ // fmt.Sprintf("hello") // } // } +// // The benchmark package will vary b.N until the benchmark function lasts // long enough to be timed reliably. The output // testing.BenchmarkHello 10000000 282 ns/op @@ -36,6 +37,33 @@ // big.Len() // } // } +// +// The package also runs and verifies example code. Example functions +// include an introductory comment that is compared with the standard output +// of the function when the tests are run, as in this example of an example: +// +// // hello +// func ExampleHello() { +// fmt.Println("hello") +// } +// +// Example functions without comments are compiled but not executed. +// +// The naming convention to declare examples for a function F, a type T and +// method M on type T are: +// +// func ExampleF() { ... } +// func ExampleT() { ... } +// func ExampleT_M() { ... } +// +// Multiple example functions for a type/function/method may be provided by +// appending a distinct suffix to the name. The suffix must start with a +// lower-case letter. +// +// func ExampleF_suffix() { ... } +// func ExampleT_suffix() { ... } +// func ExampleT_M_suffix() { ... } +// package testing import ( diff --git a/libgo/go/text/template/multi_test.go b/libgo/go/text/template/multi_test.go index 3abb51f..274f5ef 100644 --- a/libgo/go/text/template/multi_test.go +++ b/libgo/go/text/template/multi_test.go @@ -9,6 +9,7 @@ package template import ( "bytes" "fmt" + "strings" "testing" "text/template/parse" ) @@ -32,10 +33,10 @@ var multiParseTests = []multiParseTest{ nil}, {"one", `{{define "foo"}} FOO {{end}}`, noError, []string{"foo"}, - []string{`[(text: " FOO ")]`}}, + []string{`" FOO "`}}, {"two", `{{define "foo"}} FOO {{end}}{{define "bar"}} BAR {{end}}`, noError, []string{"foo", "bar"}, - []string{`[(text: " FOO ")]`, `[(text: " BAR ")]`}}, + []string{`" FOO "`, `" BAR "`}}, // errors {"missing end", `{{define "foo"}} FOO `, hasError, nil, @@ -257,3 +258,17 @@ func TestAddParseTree(t *testing.T) { t.Errorf("expected %q got %q", "broot", b.String()) } } + +func TestRedefinition(t *testing.T) { + var tmpl *Template + var err error + if tmpl, err = New("tmpl1").Parse(`{{define "test"}}foo{{end}}`); err != nil { + t.Fatalf("parse 1: %v", err) + } + if _, err = tmpl.New("tmpl2").Parse(`{{define "test"}}bar{{end}}`); err == nil { + t.Fatal("expected error") + } + if !strings.Contains(err.Error(), "redefinition") { + t.Fatalf("expected redefinition error; got %v", err) + } +} diff --git a/libgo/go/text/template/parse/node.go b/libgo/go/text/template/parse/node.go index 4f43424..0d030b8 100644 --- a/libgo/go/text/template/parse/node.go +++ b/libgo/go/text/template/parse/node.go @@ -67,11 +67,9 @@ func (l *ListNode) append(n Node) { func (l *ListNode) String() string { b := new(bytes.Buffer) - fmt.Fprint(b, "[") for _, n := range l.Nodes { fmt.Fprint(b, n) } - fmt.Fprint(b, "]") return b.String() } @@ -86,7 +84,7 @@ func newText(text string) *TextNode { } func (t *TextNode) String() string { - return fmt.Sprintf("(text: %q)", t.Text) + return fmt.Sprintf("%q", t.Text) } // PipeNode holds a pipeline with optional declaration @@ -106,10 +104,23 @@ func (p *PipeNode) append(command *CommandNode) { } func (p *PipeNode) String() string { - if p.Decl != nil { - return fmt.Sprintf("%v := %v", p.Decl, p.Cmds) + s := "" + if len(p.Decl) > 0 { + for i, v := range p.Decl { + if i > 0 { + s += ", " + } + s += v.String() + } + s += " := " + } + for i, c := range p.Cmds { + if i > 0 { + s += " | " + } + s += c.String() } - return fmt.Sprintf("%v", p.Cmds) + return s } // ActionNode holds an action (something bounded by delimiters). @@ -126,7 +137,8 @@ func newAction(line int, pipe *PipeNode) *ActionNode { } func (a *ActionNode) String() string { - return fmt.Sprintf("(action: %v)", a.Pipe) + return fmt.Sprintf("{{%s}}", a.Pipe) + } // CommandNode holds a command (a pipeline inside an evaluating action). @@ -144,7 +156,14 @@ func (c *CommandNode) append(arg Node) { } func (c *CommandNode) String() string { - return fmt.Sprintf("(command: %v)", c.Args) + s := "" + for i, arg := range c.Args { + if i > 0 { + s += " " + } + s += arg.String() + } + return s } // IdentifierNode holds an identifier. @@ -159,7 +178,7 @@ func NewIdentifier(ident string) *IdentifierNode { } func (i *IdentifierNode) String() string { - return fmt.Sprintf("I=%s", i.Ident) + return i.Ident } // VariableNode holds a list of variable names. The dollar sign is @@ -174,7 +193,14 @@ func newVariable(ident string) *VariableNode { } func (v *VariableNode) String() string { - return fmt.Sprintf("V=%s", v.Ident) + s := "" + for i, id := range v.Ident { + if i > 0 { + s += "." + } + s += id + } + return s } // DotNode holds the special identifier '.'. It is represented by a nil pointer. @@ -189,7 +215,7 @@ func (d *DotNode) Type() NodeType { } func (d *DotNode) String() string { - return "{{<.>}}" + return "." } // FieldNode holds a field (identifier starting with '.'). @@ -205,7 +231,11 @@ func newField(ident string) *FieldNode { } func (f *FieldNode) String() string { - return fmt.Sprintf("F=%s", f.Ident) + s := "" + for _, id := range f.Ident { + s += "." + id + } + return s } // BoolNode holds a boolean constant. @@ -219,7 +249,10 @@ func newBool(true bool) *BoolNode { } func (b *BoolNode) String() string { - return fmt.Sprintf("B=%t", b.True) + if b.True { + return "true" + } + return "false" } // NumberNode holds a number: signed or unsigned integer, float, or complex. @@ -337,7 +370,7 @@ func (n *NumberNode) simplifyComplex() { } func (n *NumberNode) String() string { - return fmt.Sprintf("N=%s", n.Text) + return n.Text } // StringNode holds a string constant. The value has been "unquoted". @@ -352,7 +385,7 @@ func newString(orig, text string) *StringNode { } func (s *StringNode) String() string { - return fmt.Sprintf("S=%#q", s.Text) + return s.Quoted } // endNode represents an {{end}} action. It is represented by a nil pointer. @@ -411,9 +444,9 @@ func (b *BranchNode) String() string { panic("unknown branch type") } if b.ElseList != nil { - return fmt.Sprintf("({{%s %s}} %s {{else}} %s)", name, b.Pipe, b.List, b.ElseList) + return fmt.Sprintf("{{%s %s}}%s{{else}}%s{{end}}", name, b.Pipe, b.List, b.ElseList) } - return fmt.Sprintf("({{%s %s}} %s)", name, b.Pipe, b.List) + return fmt.Sprintf("{{%s %s}}%s{{end}}", name, b.Pipe, b.List) } // IfNode represents an {{if}} action and its commands. diff --git a/libgo/go/text/template/parse/parse_test.go b/libgo/go/text/template/parse/parse_test.go index b70c214..13c5548 100644 --- a/libgo/go/text/template/parse/parse_test.go +++ b/libgo/go/text/template/parse/parse_test.go @@ -150,7 +150,7 @@ type parseTest struct { name string input string ok bool - result string + result string // what the user would see in an error message. } const ( @@ -160,59 +160,57 @@ const ( var parseTests = []parseTest{ {"empty", "", noError, - `[]`}, + ``}, {"comment", "{{/*\n\n\n*/}}", noError, - `[]`}, + ``}, {"spaces", " \t\n", noError, - `[(text: " \t\n")]`}, + `" \t\n"`}, {"text", "some text", noError, - `[(text: "some text")]`}, + `"some text"`}, {"emptyAction", "{{}}", hasError, - `[(action: [])]`}, + `{{}}`}, {"field", "{{.X}}", noError, - `[(action: [(command: [F=[X]])])]`}, + `{{.X}}`}, {"simple command", "{{printf}}", noError, - `[(action: [(command: [I=printf])])]`}, + `{{printf}}`}, {"$ invocation", "{{$}}", noError, - "[(action: [(command: [V=[$]])])]"}, + "{{$}}"}, {"variable invocation", "{{with $x := 3}}{{$x 23}}{{end}}", noError, - "[({{with [V=[$x]] := [(command: [N=3])]}} [(action: [(command: [V=[$x] N=23])])])]"}, + "{{with $x := 3}}{{$x 23}}{{end}}"}, {"variable with fields", "{{$.I}}", noError, - "[(action: [(command: [V=[$ I]])])]"}, + "{{$.I}}"}, {"multi-word command", "{{printf `%d` 23}}", noError, - "[(action: [(command: [I=printf S=`%d` N=23])])]"}, + "{{printf `%d` 23}}"}, {"pipeline", "{{.X|.Y}}", noError, - `[(action: [(command: [F=[X]]) (command: [F=[Y]])])]`}, + `{{.X | .Y}}`}, {"pipeline with decl", "{{$x := .X|.Y}}", noError, - `[(action: [V=[$x]] := [(command: [F=[X]]) (command: [F=[Y]])])]`}, - {"declaration", "{{.X|.Y}}", noError, - `[(action: [(command: [F=[X]]) (command: [F=[Y]])])]`}, + `{{$x := .X | .Y}}`}, {"simple if", "{{if .X}}hello{{end}}", noError, - `[({{if [(command: [F=[X]])]}} [(text: "hello")])]`}, + `{{if .X}}"hello"{{end}}`}, {"if with else", "{{if .X}}true{{else}}false{{end}}", noError, - `[({{if [(command: [F=[X]])]}} [(text: "true")] {{else}} [(text: "false")])]`}, + `{{if .X}}"true"{{else}}"false"{{end}}`}, {"simple range", "{{range .X}}hello{{end}}", noError, - `[({{range [(command: [F=[X]])]}} [(text: "hello")])]`}, + `{{range .X}}"hello"{{end}}`}, {"chained field range", "{{range .X.Y.Z}}hello{{end}}", noError, - `[({{range [(command: [F=[X Y Z]])]}} [(text: "hello")])]`}, + `{{range .X.Y.Z}}"hello"{{end}}`}, {"nested range", "{{range .X}}hello{{range .Y}}goodbye{{end}}{{end}}", noError, - `[({{range [(command: [F=[X]])]}} [(text: "hello")({{range [(command: [F=[Y]])]}} [(text: "goodbye")])])]`}, + `{{range .X}}"hello"{{range .Y}}"goodbye"{{end}}{{end}}`}, {"range with else", "{{range .X}}true{{else}}false{{end}}", noError, - `[({{range [(command: [F=[X]])]}} [(text: "true")] {{else}} [(text: "false")])]`}, + `{{range .X}}"true"{{else}}"false"{{end}}`}, {"range over pipeline", "{{range .X|.M}}true{{else}}false{{end}}", noError, - `[({{range [(command: [F=[X]]) (command: [F=[M]])]}} [(text: "true")] {{else}} [(text: "false")])]`}, + `{{range .X | .M}}"true"{{else}}"false"{{end}}`}, {"range []int", "{{range .SI}}{{.}}{{end}}", noError, - `[({{range [(command: [F=[SI]])]}} [(action: [(command: [{{<.>}}])])])]`}, + `{{range .SI}}{{.}}{{end}}`}, {"constants", "{{range .SI 1 -3.2i true false 'a'}}{{end}}", noError, - `[({{range [(command: [F=[SI] N=1 N=-3.2i B=true B=false N='a'])]}} [])]`}, + `{{range .SI 1 -3.2i true false 'a'}}{{end}}`}, {"template", "{{template `x`}}", noError, - `[{{template "x"}}]`}, + `{{template "x"}}`}, {"template with arg", "{{template `x` .Y}}", noError, - `[{{template "x" [(command: [F=[Y]])]}}]`}, + `{{template "x" .Y}}`}, {"with", "{{with .X}}hello{{end}}", noError, - `[({{with [(command: [F=[X]])]}} [(text: "hello")])]`}, + `{{with .X}}"hello"{{end}}`}, {"with with else", "{{with .X}}hello{{else}}goodbye{{end}}", noError, - `[({{with [(command: [F=[X]])]}} [(text: "hello")] {{else}} [(text: "goodbye")])]`}, + `{{with .X}}"hello"{{else}}"goodbye"{{end}}`}, // Errors. {"unclosed action", "hello{{range", hasError, ""}, {"unmatched end", "{{end}}", hasError, ""}, diff --git a/libgo/go/text/template/template.go b/libgo/go/text/template/template.go index cbc6808..87e39d3 100644 --- a/libgo/go/text/template/template.go +++ b/libgo/go/text/template/template.go @@ -198,7 +198,7 @@ func (t *Template) associate(new *Template) error { name := new.name if old := t.tmpl[name]; old != nil { oldIsEmpty := parse.IsEmptyTree(old.Root) - newIsEmpty := parse.IsEmptyTree(new.Root) + newIsEmpty := new.Tree != nil && parse.IsEmptyTree(new.Root) if !oldIsEmpty && !newIsEmpty { return fmt.Errorf("template: redefinition of template %q", name) } diff --git a/libgo/go/time/format.go b/libgo/go/time/format.go index bd02b48..76bf6ff 100644 --- a/libgo/go/time/format.go +++ b/libgo/go/time/format.go @@ -1,3 +1,7 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package time import "errors" diff --git a/libgo/go/time/time.go b/libgo/go/time/time.go index 33d557f..39d4b95 100644 --- a/libgo/go/time/time.go +++ b/libgo/go/time/time.go @@ -130,7 +130,7 @@ var days = [...]string{ func (d Weekday) String() string { return days[d] } // Computations on time. -// +// // The zero value for a Time is defined to be // January 1, year 1, 00:00:00.000000000 UTC // which (1) looks like a zero, or as close as you can get in a date @@ -138,16 +138,16 @@ func (d Weekday) String() string { return days[d] } // be a suitable "not set" sentinel, unlike Jan 1 1970, and (3) has a // non-negative year even in time zones west of UTC, unlike 1-1-0 // 00:00:00 UTC, which would be 12-31-(-1) 19:00:00 in New York. -// +// // The zero Time value does not force a specific epoch for the time // representation. For example, to use the Unix epoch internally, we // could define that to distinguish a zero value from Jan 1 1970, that // time would be represented by sec=-1, nsec=1e9. However, it does // suggest a representation, namely using 1-1-1 00:00:00 UTC as the // epoch, and that's what we do. -// +// // The Add and Sub computations are oblivious to the choice of epoch. -// +// // The presentation computations - year, month, minute, and so on - all // rely heavily on division and modulus by positive constants. For // calendrical calculations we want these divisions to round down, even @@ -172,7 +172,7 @@ func (d Weekday) String() string { return days[d] } // } // // everywhere. -// +// // The calendar runs on an exact 400 year cycle: a 400-year calendar // printed for 1970-2469 will apply as well to 2470-2869. Even the days // of the week match up. It simplifies the computations to choose the @@ -182,22 +182,22 @@ func (d Weekday) String() string { return days[d] } // is the 100th year, and the missed missed leap year is the 400th year. // So we'd prefer instead to print a calendar for 2001-2400 and reuse it // for 2401-2800. -// +// // Finally, it's convenient if the delta between the Unix epoch and // long-ago epoch is representable by an int64 constant. -// +// // These three considerations—choose an epoch as early as possible, that // uses a year equal to 1 mod 400, and that is no more than 2⁶³ seconds // earlier than 1970—bring us to the year -292277022399. We refer to // this year as the absolute zero year, and to times measured as a uint64 // seconds since this year as absolute times. -// +// // Times measured as an int64 seconds since the year 1—the representation // used for Time's sec field—are called internal times. -// +// // Times measured as an int64 seconds since the year 1970 are called Unix // times. -// +// // It is tempting to just use the year 1 as the absolute epoch, defining // that the routines are only valid for years >= 1. However, the // routines would then be invalid when displaying the epoch in time zones @@ -205,7 +205,7 @@ func (d Weekday) String() string { return days[d] } // printing the zero time correctly isn't supported in half the time // zones. By comparison, it's reasonable to mishandle some times in // the year -292277022399. -// +// // All this is opaque to clients of the API and can be changed if a // better implementation presents itself. @@ -288,8 +288,8 @@ func (t Time) Weekday() Weekday { } // ISOWeek returns the ISO 8601 year and week number in which t occurs. -// Week ranges from 1 to 53. Jan 01 to Jan 03 of year n might belong to -// week 52 or 53 of year n-1, and Dec 29 to Dec 31 might belong to week 1 +// Week ranges from 1 to 53. Jan 01 to Jan 03 of year n might belong to +// week 52 or 53 of year n-1, and Dec 29 to Dec 31 might belong to week 1 // of year n+1. func (t Time) ISOWeek() (year, week int) { year, month, day, yday := t.date(true) @@ -566,6 +566,12 @@ func (t Time) Sub(u Time) Duration { return Duration(t.sec-u.sec)*Second + Duration(t.nsec-u.nsec) } +// Since returns the time elapsed since t. +// It is shorthand for time.Now().Sub(t). +func Since(t Time) Duration { + return Now().Sub(t) +} + // 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 diff --git a/libgo/go/unicode/utf8/string.go b/libgo/go/unicode/utf8/string.go deleted file mode 100644 index 443decf..0000000 --- a/libgo/go/unicode/utf8/string.go +++ /dev/null @@ -1,199 +0,0 @@ -// 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 utf8 - -import "errors" - -// String wraps a regular string with a small structure that provides more -// efficient indexing by code point index, as opposed to byte index. -// Scanning incrementally forwards or backwards is O(1) per index operation -// (although not as fast a range clause going forwards). Random access is -// O(N) in the length of the string, but the overhead is less than always -// scanning from the beginning. -// If the string is ASCII, random access is O(1). -// Unlike the built-in string type, String has internal mutable state and -// is not thread-safe. -type String struct { - str string - numRunes int - // If width > 0, the rune at runePos starts at bytePos and has the specified width. - width int - bytePos int - runePos int - nonASCII int // byte index of the first non-ASCII rune. -} - -// NewString returns a new UTF-8 string with the provided contents. -func NewString(contents string) *String { - return new(String).Init(contents) -} - -// Init initializes an existing String to hold the provided contents. -// It returns a pointer to the initialized String. -func (s *String) Init(contents string) *String { - s.str = contents - s.bytePos = 0 - s.runePos = 0 - for i := 0; i < len(contents); i++ { - if contents[i] >= RuneSelf { - // Not ASCII. - s.numRunes = RuneCountInString(contents) - _, s.width = DecodeRuneInString(contents) - s.nonASCII = i - return s - } - } - // ASCII is simple. Also, the empty string is ASCII. - s.numRunes = len(contents) - s.width = 0 - s.nonASCII = len(contents) - return s -} - -// String returns the contents of the String. This method also means the -// String is directly printable by fmt.Print. -func (s *String) String() string { - return s.str -} - -// RuneCount returns the number of runes (Unicode code points) in the String. -func (s *String) RuneCount() int { - return s.numRunes -} - -// IsASCII returns a boolean indicating whether the String contains only ASCII bytes. -func (s *String) IsASCII() bool { - return s.width == 0 -} - -// Slice returns the string sliced at rune positions [i:j]. -func (s *String) Slice(i, j int) string { - // ASCII is easy. Let the compiler catch the indexing error if there is one. - if j < s.nonASCII { - return s.str[i:j] - } - if i < 0 || j > s.numRunes || i > j { - panic(sliceOutOfRange) - } - if i == j { - return "" - } - // For non-ASCII, after At(i), bytePos is always the position of the indexed character. - var low, high int - switch { - case i < s.nonASCII: - low = i - case i == s.numRunes: - low = len(s.str) - default: - s.At(i) - low = s.bytePos - } - switch { - case j == s.numRunes: - high = len(s.str) - default: - s.At(j) - high = s.bytePos - } - return s.str[low:high] -} - -// At returns the rune with index i in the String. The sequence of runes is the same -// as iterating over the contents with a "for range" clause. -func (s *String) At(i int) rune { - // ASCII is easy. Let the compiler catch the indexing error if there is one. - if i < s.nonASCII { - return rune(s.str[i]) - } - - // Now we do need to know the index is valid. - if i < 0 || i >= s.numRunes { - panic(outOfRange) - } - - var r rune - - // Five easy common cases: within 1 spot of bytePos/runePos, or the beginning, or the end. - // With these cases, all scans from beginning or end work in O(1) time per rune. - switch { - - case i == s.runePos-1: // backing up one rune - r, s.width = DecodeLastRuneInString(s.str[0:s.bytePos]) - s.runePos = i - s.bytePos -= s.width - return r - case i == s.runePos+1: // moving ahead one rune - s.runePos = i - s.bytePos += s.width - fallthrough - case i == s.runePos: - r, s.width = DecodeRuneInString(s.str[s.bytePos:]) - return r - case i == 0: // start of string - r, s.width = DecodeRuneInString(s.str) - s.runePos = 0 - s.bytePos = 0 - return r - - case i == s.numRunes-1: // last rune in string - r, s.width = DecodeLastRuneInString(s.str) - s.runePos = i - s.bytePos = len(s.str) - s.width - return r - } - - // We need to do a linear scan. There are three places to start from: - // 1) The beginning - // 2) bytePos/runePos. - // 3) The end - // Choose the closest in rune count, scanning backwards if necessary. - forward := true - if i < s.runePos { - // Between beginning and pos. Which is closer? - // Since both i and runePos are guaranteed >= nonASCII, that's the - // lowest location we need to start from. - if i < (s.runePos-s.nonASCII)/2 { - // Scan forward from beginning - s.bytePos, s.runePos = s.nonASCII, s.nonASCII - } else { - // Scan backwards from where we are - forward = false - } - } else { - // Between pos and end. Which is closer? - if i-s.runePos < (s.numRunes-s.runePos)/2 { - // Scan forward from pos - } else { - // Scan backwards from end - s.bytePos, s.runePos = len(s.str), s.numRunes - forward = false - } - } - if forward { - // TODO: Is it much faster to use a range loop for this scan? - for { - r, s.width = DecodeRuneInString(s.str[s.bytePos:]) - if s.runePos == i { - break - } - s.runePos++ - s.bytePos += s.width - } - } else { - for { - r, s.width = DecodeLastRuneInString(s.str[0:s.bytePos]) - s.runePos-- - s.bytePos -= s.width - if s.runePos == i { - break - } - } - } - return r -} - -var outOfRange = errors.New("utf8.String: index out of range") -var sliceOutOfRange = errors.New("utf8.String: slice index out of range") diff --git a/libgo/go/unicode/utf8/string_test.go b/libgo/go/unicode/utf8/string_test.go deleted file mode 100644 index 2c139be..0000000 --- a/libgo/go/unicode/utf8/string_test.go +++ /dev/null @@ -1,114 +0,0 @@ -// 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 utf8_test - -import ( - "math/rand" - "testing" - . "unicode/utf8" -) - -func TestScanForwards(t *testing.T) { - for _, s := range testStrings { - runes := []rune(s) - str := NewString(s) - if str.RuneCount() != len(runes) { - t.Errorf("%s: expected %d runes; got %d", s, len(runes), str.RuneCount()) - break - } - for i, expect := range runes { - got := str.At(i) - if got != expect { - t.Errorf("%s[%d]: expected %c (%U); got %c (%U)", s, i, expect, expect, got, got) - } - } - } -} - -func TestScanBackwards(t *testing.T) { - for _, s := range testStrings { - runes := []rune(s) - str := NewString(s) - if str.RuneCount() != len(runes) { - t.Errorf("%s: expected %d runes; got %d", s, len(runes), str.RuneCount()) - break - } - for i := len(runes) - 1; i >= 0; i-- { - expect := runes[i] - got := str.At(i) - if got != expect { - t.Errorf("%s[%d]: expected %c (%U); got %c (%U)", s, i, expect, expect, got, got) - } - } - } -} - -func randCount() int { - if testing.Short() { - return 100 - } - return 100000 -} - -func TestRandomAccess(t *testing.T) { - for _, s := range testStrings { - if len(s) == 0 { - continue - } - runes := []rune(s) - str := NewString(s) - if str.RuneCount() != len(runes) { - t.Errorf("%s: expected %d runes; got %d", s, len(runes), str.RuneCount()) - break - } - for j := 0; j < randCount(); j++ { - i := rand.Intn(len(runes)) - expect := runes[i] - got := str.At(i) - if got != expect { - t.Errorf("%s[%d]: expected %c (%U); got %c (%U)", s, i, expect, expect, got, got) - } - } - } -} - -func TestRandomSliceAccess(t *testing.T) { - for _, s := range testStrings { - if len(s) == 0 || s[0] == '\x80' { // the bad-UTF-8 string fools this simple test - continue - } - runes := []rune(s) - str := NewString(s) - if str.RuneCount() != len(runes) { - t.Errorf("%s: expected %d runes; got %d", s, len(runes), str.RuneCount()) - break - } - for k := 0; k < randCount(); k++ { - i := rand.Intn(len(runes)) - j := rand.Intn(len(runes) + 1) - if i > j { // include empty strings - continue - } - expect := string(runes[i:j]) - got := str.Slice(i, j) - if got != expect { - t.Errorf("%s[%d:%d]: expected %q got %q", s, i, j, expect, got) - } - } - } -} - -func TestLimitSliceAccess(t *testing.T) { - for _, s := range testStrings { - str := NewString(s) - if str.Slice(0, 0) != "" { - t.Error("failure with empty slice at beginning") - } - nr := RuneCountInString(s) - if str.Slice(nr, nr) != "" { - t.Error("failure with empty slice at end") - } - } -} diff --git a/libgo/go/websocket/hixie.go b/libgo/go/websocket/hixie.go index d0ddbee..22dbc1f 100644 --- a/libgo/go/websocket/hixie.go +++ b/libgo/go/websocket/hixie.go @@ -343,7 +343,7 @@ func hixie76ClientHandshake(config *Config, br *bufio.Reader, bw *bufio.Writer) } // 4.1. Opening handshake. // Step 5. send a request line. - bw.WriteString("GET " + config.Location.RawPath + " HTTP/1.1\r\n") + bw.WriteString("GET " + config.Location.RequestURI() + " HTTP/1.1\r\n") // Step 6-14. push request headers in fields. fields := []string{ @@ -456,7 +456,7 @@ func hixie75ClientHandshake(config *Config, br *bufio.Reader, bw *bufio.Writer) if config.Version != ProtocolVersionHixie75 { panic("wrong protocol version.") } - bw.WriteString("GET " + config.Location.RawPath + " HTTP/1.1\r\n") + bw.WriteString("GET " + config.Location.RequestURI() + " HTTP/1.1\r\n") bw.WriteString("Upgrade: WebSocket\r\n") bw.WriteString("Connection: Upgrade\r\n") bw.WriteString("Host: " + config.Location.Host + "\r\n") @@ -557,7 +557,7 @@ func (c *hixie76ServerHandshaker) ReadHandshake(buf *bufio.Reader, req *http.Req } else { scheme = "ws" } - c.Location, err = url.ParseRequest(scheme + "://" + req.Host + req.URL.RawPath) + c.Location, err = url.ParseRequest(scheme + "://" + req.Host + req.URL.RequestURI()) if err != nil { return http.StatusBadRequest, err } @@ -653,7 +653,7 @@ func (c *hixie75ServerHandshaker) ReadHandshake(buf *bufio.Reader, req *http.Req } else { scheme = "ws" } - c.Location, err = url.ParseRequest(scheme + "://" + req.Host + req.URL.RawPath) + c.Location, err = url.ParseRequest(scheme + "://" + req.Host + req.URL.RequestURI()) if err != nil { return http.StatusBadRequest, err } diff --git a/libgo/go/websocket/hybi.go b/libgo/go/websocket/hybi.go index ff386dc..6b0c528 100644 --- a/libgo/go/websocket/hybi.go +++ b/libgo/go/websocket/hybi.go @@ -390,7 +390,7 @@ func hybiClientHandshake(config *Config, br *bufio.Reader, bw *bufio.Writer) (er panic("wrong protocol version.") } - bw.WriteString("GET " + config.Location.RawPath + " HTTP/1.1\r\n") + bw.WriteString("GET " + config.Location.RequestURI() + " HTTP/1.1\r\n") bw.WriteString("Host: " + config.Location.Host + "\r\n") bw.WriteString("Upgrade: websocket\r\n") @@ -505,7 +505,7 @@ func (c *hybiServerHandshaker) ReadHandshake(buf *bufio.Reader, req *http.Reques } else { scheme = "ws" } - c.Location, err = url.ParseRequest(scheme + "://" + req.Host + req.URL.RawPath) + c.Location, err = url.ParseRequest(scheme + "://" + req.Host + req.URL.RequestURI()) if err != nil { return http.StatusBadRequest, err } diff --git a/libgo/go/websocket/websocket.go b/libgo/go/websocket/websocket.go index df4416e..f7aabc9 100644 --- a/libgo/go/websocket/websocket.go +++ b/libgo/go/websocket/websocket.go @@ -17,6 +17,7 @@ import ( "net/http" "net/url" "sync" + "time" ) const ( @@ -243,30 +244,30 @@ func (ws *Conn) RemoteAddr() net.Addr { return &Addr{ws.config.Origin} } -var errSetTimeout = errors.New("websocket: cannot set timeout: not using a net.Conn") +var errSetDeadline = errors.New("websocket: cannot set deadline: not using a net.Conn") -// SetTimeout sets the connection's network timeout in nanoseconds. -func (ws *Conn) SetTimeout(nsec int64) error { +// SetDeadline sets the connection's network read & write deadlines. +func (ws *Conn) SetDeadline(t time.Time) error { if conn, ok := ws.rwc.(net.Conn); ok { - return conn.SetTimeout(nsec) + return conn.SetDeadline(t) } - return errSetTimeout + return errSetDeadline } -// SetReadTimeout sets the connection's network read timeout in nanoseconds. -func (ws *Conn) SetReadTimeout(nsec int64) error { +// SetReadDeadline sets the connection's network read deadline. +func (ws *Conn) SetReadDeadline(t time.Time) error { if conn, ok := ws.rwc.(net.Conn); ok { - return conn.SetReadTimeout(nsec) + return conn.SetReadDeadline(t) } - return errSetTimeout + return errSetDeadline } -// SetWriteTimeout sets the connection's network write timeout in nanoseconds. -func (ws *Conn) SetWriteTimeout(nsec int64) error { +// SetWriteDeadline sets the connection's network write deadline. +func (ws *Conn) SetWriteDeadline(t time.Time) error { if conn, ok := ws.rwc.(net.Conn); ok { - return conn.SetWriteTimeout(nsec) + return conn.SetWriteDeadline(t) } - return errSetTimeout + return errSetDeadline } // Config returns the WebSocket config. -- cgit v1.1