From 7b1c3dd9e670da2041ff1af415999310f88888ad Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 13 Dec 2011 19:16:27 +0000 Subject: [PATCH] libgo: Update to weekly.2011-12-02. From-SVN: r182295 --- .../go.test/test/fixedbugs/bug257.go | 5 +- gcc/testsuite/go.test/test/initsyscall.go | 3 +- libgo/MERGE | 2 +- libgo/Makefile.am | 51 +- libgo/Makefile.in | 168 +-- libgo/go/archive/tar/common.go | 53 +- libgo/go/archive/tar/reader.go | 7 +- libgo/go/archive/tar/reader_test.go | 55 +- libgo/go/archive/tar/writer.go | 26 +- libgo/go/archive/tar/writer_test.go | 9 +- libgo/go/archive/zip/reader.go | 2 +- libgo/go/archive/zip/reader_test.go | 4 +- libgo/go/archive/zip/struct.go | 32 +- libgo/go/bytes/bytes_test.go | 2 +- libgo/go/compress/gzip/gunzip.go | 13 +- libgo/go/compress/gzip/gzip.go | 2 +- libgo/go/compress/gzip/gzip_test.go | 7 +- libgo/go/crypto/bcrypt/bcrypt.go | 2 +- libgo/go/crypto/ecdsa/ecdsa_test.go | 2 +- libgo/go/crypto/hmac/hmac.go | 8 +- libgo/go/crypto/hmac/hmac_test.go | 2 +- libgo/go/crypto/md4/md4.go | 15 +- libgo/go/crypto/md4/md4_test.go | 4 +- libgo/go/crypto/md5/md5.go | 15 +- libgo/go/crypto/md5/md5_test.go | 4 +- libgo/go/crypto/ocsp/ocsp.go | 12 +- libgo/go/crypto/ocsp/ocsp_test.go | 8 +- libgo/go/crypto/openpgp/canonical_text.go | 4 +- .../go/crypto/openpgp/canonical_text_test.go | 6 +- libgo/go/crypto/openpgp/keys.go | 18 +- libgo/go/crypto/openpgp/packet/private_key.go | 17 +- .../crypto/openpgp/packet/private_key_test.go | 9 +- libgo/go/crypto/openpgp/packet/public_key.go | 22 +- .../crypto/openpgp/packet/public_key_test.go | 11 +- libgo/go/crypto/openpgp/packet/signature.go | 19 +- .../openpgp/packet/symmetrically_encrypted.go | 4 +- libgo/go/crypto/openpgp/s2k/s2k.go | 4 +- libgo/go/crypto/openpgp/write.go | 20 +- libgo/go/crypto/openpgp/write_test.go | 2 +- libgo/go/crypto/rand/rand_unix.go | 2 +- libgo/go/crypto/ripemd160/ripemd160.go | 12 +- libgo/go/crypto/ripemd160/ripemd160_test.go | 6 +- libgo/go/crypto/rsa/pkcs1v15_test.go | 4 +- libgo/go/crypto/rsa/rsa.go | 6 +- libgo/go/crypto/sha1/sha1.go | 15 +- libgo/go/crypto/sha1/sha1_test.go | 4 +- libgo/go/crypto/sha256/sha256.go | 22 +- libgo/go/crypto/sha256/sha256_test.go | 8 +- libgo/go/crypto/sha512/sha512.go | 30 +- libgo/go/crypto/sha512/sha512_test.go | 8 +- libgo/go/crypto/tls/cipher_suites.go | 34 +- libgo/go/crypto/tls/common.go | 12 +- libgo/go/crypto/tls/handshake_client.go | 10 +- libgo/go/crypto/tls/handshake_server.go | 23 +- libgo/go/crypto/tls/handshake_server_test.go | 3 +- libgo/go/crypto/tls/key_agreement.go | 4 +- libgo/go/crypto/tls/prf.go | 26 +- libgo/go/crypto/tls/root_unix.go | 1 + libgo/go/crypto/tls/root_windows.go | 27 +- libgo/go/crypto/tls/tls.go | 19 +- libgo/go/crypto/x509/cert_pool.go | 10 +- libgo/go/crypto/x509/pkcs8.go | 42 + libgo/go/crypto/x509/pkcs8_test.go | 20 + libgo/go/crypto/x509/pkix/pkix.go | 13 +- libgo/go/crypto/x509/verify.go | 12 +- libgo/go/crypto/x509/verify_test.go | 3 +- libgo/go/crypto/x509/x509.go | 21 +- libgo/go/crypto/x509/x509_test.go | 12 +- libgo/go/encoding/asn1/asn1.go | 10 +- libgo/go/encoding/asn1/asn1_test.go | 61 +- libgo/go/encoding/asn1/marshal.go | 38 +- libgo/go/encoding/asn1/marshal_test.go | 14 +- libgo/go/encoding/json/encode.go | 89 +- libgo/go/encoding/xml/xml.go | 2 +- libgo/go/encoding/xml/xml_test.go | 107 +- libgo/go/exp/gotype/gotype.go | 12 +- libgo/go/exp/gui/gui.go | 57 - libgo/go/exp/gui/x11/auth.go | 96 -- libgo/go/exp/gui/x11/conn.go | 631 ---------- libgo/go/exp/sql/driver/driver.go | 31 +- libgo/go/exp/sql/fakedb_test.go | 14 + libgo/go/exp/sql/sql.go | 79 +- libgo/go/exp/sql/sql_test.go | 78 +- libgo/go/exp/ssh/channel.go | 12 +- libgo/go/exp/ssh/client.go | 67 +- libgo/go/exp/ssh/client_auth_test.go | 2 +- libgo/go/exp/ssh/common.go | 13 + libgo/go/exp/ssh/common_test.go | 26 + libgo/go/exp/ssh/doc.go | 4 +- libgo/go/exp/ssh/server.go | 6 +- libgo/go/exp/ssh/session.go | 460 +++++-- libgo/go/exp/ssh/session_test.go | 149 +++ libgo/go/exp/ssh/tcpip.go | 4 +- libgo/go/exp/ssh/tcpip_func_test.go | 59 + libgo/go/exp/ssh/transport.go | 12 +- libgo/go/exp/types/check_test.go | 2 +- libgo/go/exp/types/gcimporter.go | 2 +- libgo/go/exp/types/gcimporter_test.go | 18 +- libgo/go/fmt/fmt_test.go | 16 +- libgo/go/fmt/print.go | 2 +- libgo/go/go/ast/resolve.go | 2 +- libgo/go/go/build/build.go | 9 +- libgo/go/go/build/dir.go | 35 +- libgo/go/go/build/path.go | 4 +- libgo/go/go/doc/comment.go | 74 ++ libgo/go/go/doc/comment_test.go | 39 + libgo/go/go/doc/headscan.go | 111 ++ libgo/go/go/parser/interface.go | 7 +- libgo/go/go/parser/parser_test.go | 2 +- libgo/go/go/printer/nodes.go | 2 +- libgo/go/go/printer/performance_test.go | 2 +- libgo/go/go/printer/printer.go | 399 +++--- libgo/go/go/printer/printer_test.go | 2 +- libgo/go/hash/adler32/adler32.go | 13 +- libgo/go/hash/crc32/crc32.go | 13 +- libgo/go/hash/crc64/crc64.go | 21 +- libgo/go/hash/fnv/fnv.go | 53 +- libgo/go/hash/fnv/fnv_test.go | 12 +- libgo/go/hash/hash.go | 6 +- libgo/go/html/doctype.go | 156 +++ libgo/go/html/parse.go | 179 ++- libgo/go/html/parse_test.go | 184 +-- libgo/go/html/render.go | 68 +- libgo/go/html/template/clone_test.go | 34 +- libgo/go/html/template/content.go | 12 +- libgo/go/html/template/doc.go | 68 +- libgo/go/html/template/escape.go | 51 +- libgo/go/html/template/escape_test.go | 38 +- libgo/go/html/template/template.go | 392 +++--- libgo/go/html/token.go | 60 +- libgo/go/html/token_test.go | 20 + libgo/go/io/ioutil/ioutil.go | 24 +- libgo/go/io/ioutil/ioutil_test.go | 8 +- libgo/go/io/ioutil/tempfile.go | 2 +- libgo/go/io/multi_test.go | 2 +- libgo/go/log/log.go | 21 +- libgo/go/math/abs.go | 3 +- libgo/go/math/asinh.go | 3 +- libgo/go/math/big/calibrate_test.go | 10 +- libgo/go/math/big/int_test.go | 8 +- libgo/go/math/big/nat.go | 229 +++- libgo/go/math/big/nat_test.go | 244 ++-- libgo/go/math/cbrt.go | 13 +- libgo/go/math/floor.go | 9 +- libgo/go/math/gamma.go | 3 +- libgo/go/math/log1p.go | 3 +- libgo/go/math/modf.go | 3 +- libgo/go/math/sincos.go | 62 +- libgo/go/net/dnsclient_unix.go | 2 +- libgo/go/net/fd.go | 2 +- libgo/go/net/fd_windows.go | 3 +- libgo/go/net/hosts.go | 10 +- libgo/go/net/http/cgi/host_test.go | 2 +- libgo/go/net/http/cookie.go | 6 +- libgo/go/net/http/cookie_test.go | 2 +- libgo/go/net/http/export_test.go | 6 +- libgo/go/net/http/fcgi/child.go | 2 +- libgo/go/net/http/fs.go | 20 +- libgo/go/net/http/fs_test.go | 4 +- libgo/go/net/http/httptest/server.go | 4 - libgo/go/net/http/httputil/reverseproxy.go | 10 +- libgo/go/net/http/pprof/pprof.go | 2 +- libgo/go/net/http/serve_test.go | 12 +- libgo/go/net/http/server.go | 17 +- libgo/go/net/http/sniff.go | 34 +- libgo/go/net/http/sniff_test.go | 23 + libgo/go/net/http/transport_test.go | 2 +- libgo/go/net/mail/message.go | 10 +- libgo/go/net/mail/message_test.go | 22 +- libgo/go/net/timeout_test.go | 8 +- libgo/go/old/netchan/common.go | 12 +- libgo/go/old/netchan/export.go | 14 +- libgo/go/old/netchan/import.go | 4 +- libgo/go/os/exec/lp_unix.go | 2 +- libgo/go/os/exec/lp_windows.go | 6 +- libgo/go/os/export_test.go | 9 + libgo/go/os/file.go | 54 +- libgo/go/os/file_posix.go | 16 +- libgo/go/os/file_unix.go | 69 +- libgo/go/os/getwd.go | 12 +- libgo/go/os/os_test.go | 146 +-- libgo/go/os/os_unix_test.go | 75 ++ libgo/go/os/path.go | 6 +- libgo/go/os/stat.go | 72 +- libgo/go/os/stat_openbsd.go | 66 +- libgo/go/os/types.go | 132 +- libgo/go/os/user/user_test.go | 4 +- libgo/go/patch/git.go | 2 +- libgo/go/path/filepath/match.go | 2 +- libgo/go/path/filepath/path.go | 38 +- libgo/go/path/filepath/path_test.go | 21 +- libgo/go/strings/strings.go | 16 +- libgo/go/strings/strings_test.go | 52 +- libgo/go/testing/benchmark.go | 44 +- libgo/go/testing/example.go | 6 +- libgo/go/testing/testing.go | 21 +- libgo/go/text/template/doc.go | 80 +- libgo/go/text/template/exec.go | 35 +- libgo/go/text/template/exec_test.go | 37 +- libgo/go/text/template/funcs.go | 17 +- libgo/go/text/template/helper.go | 253 +--- libgo/go/text/template/multi_test.go | 288 +++++ libgo/go/text/template/parse.go | 83 -- libgo/go/text/template/parse/parse.go | 57 +- libgo/go/text/template/parse/parse_test.go | 2 +- libgo/go/text/template/parse/set.go | 15 - libgo/go/text/template/set.go | 121 -- libgo/go/text/template/set_test.go | 239 ---- libgo/go/text/template/template.go | 236 ++++ libgo/go/text/template/testdata/tmpl1.tmpl | 2 + libgo/go/text/template/testdata/tmpl2.tmpl | 2 + libgo/go/time/example_test.go | 58 + libgo/go/time/format.go | 451 ++++--- libgo/go/time/internal_test.go | 2 +- libgo/go/time/sleep.go | 23 +- libgo/go/time/sleep_test.go | 72 +- libgo/go/time/sys.go | 42 +- libgo/go/time/sys_unix.go | 7 +- libgo/go/time/tick.go | 26 +- libgo/go/time/tick_test.go | 14 +- libgo/go/time/time.go | 1071 +++++++++++++---- libgo/go/time/time_test.go | 322 +++-- libgo/go/time/zoneinfo.go | 191 +++ libgo/go/time/zoneinfo_plan9.go | 23 +- libgo/go/time/zoneinfo_posix.go | 64 - libgo/go/time/zoneinfo_unix.go | 141 ++- libgo/go/time/zoneinfo_windows.go | 280 ++--- libgo/go/websocket/client.go | 2 +- libgo/go/websocket/hixie.go | 2 +- libgo/go/websocket/hybi.go | 2 +- libgo/go/websocket/server.go | 2 +- libgo/runtime/go-nanotime.c | 9 +- libgo/runtime/go-now.c | 31 + libgo/runtime/time.goc | 5 +- 234 files changed, 6653 insertions(+), 4704 deletions(-) create mode 100644 libgo/go/crypto/x509/pkcs8.go create mode 100644 libgo/go/crypto/x509/pkcs8_test.go delete mode 100644 libgo/go/exp/gui/gui.go delete mode 100644 libgo/go/exp/gui/x11/auth.go delete mode 100644 libgo/go/exp/gui/x11/conn.go create mode 100644 libgo/go/exp/ssh/common_test.go create mode 100644 libgo/go/exp/ssh/session_test.go create mode 100644 libgo/go/exp/ssh/tcpip_func_test.go create mode 100644 libgo/go/go/doc/comment_test.go create mode 100644 libgo/go/go/doc/headscan.go create mode 100644 libgo/go/html/doctype.go create mode 100644 libgo/go/os/export_test.go create mode 100644 libgo/go/os/os_unix_test.go create mode 100644 libgo/go/text/template/multi_test.go delete mode 100644 libgo/go/text/template/parse.go delete mode 100644 libgo/go/text/template/parse/set.go delete mode 100644 libgo/go/text/template/set.go delete mode 100644 libgo/go/text/template/set_test.go create mode 100644 libgo/go/text/template/template.go create mode 100644 libgo/go/time/example_test.go create mode 100644 libgo/go/time/zoneinfo.go delete mode 100644 libgo/go/time/zoneinfo_posix.go create mode 100644 libgo/runtime/go-now.c diff --git a/gcc/testsuite/go.test/test/fixedbugs/bug257.go b/gcc/testsuite/go.test/test/fixedbugs/bug257.go index 713c42481f8..1b32475003a 100644 --- a/gcc/testsuite/go.test/test/fixedbugs/bug257.go +++ b/gcc/testsuite/go.test/test/fixedbugs/bug257.go @@ -20047,11 +20047,10 @@ var gettysburg = " Four score and seven years ago our fathers brought forth on\ "\n" + "Abraham Lincoln, November 19, 1863, Gettysburg, Pennsylvania\n" - func main() { m := md5.New() io.WriteString(m, data) - hash := fmt.Sprintf("%x", m.Sum()) + hash := fmt.Sprintf("%x", m.Sum(nil)) if hash != "525f06bc62a65017cd2217d7584e5920" { println("BUG a", hash) return @@ -20059,7 +20058,7 @@ func main() { m = md5.New() io.WriteString(m, gettysburg) - hash = fmt.Sprintf("%x", m.Sum()) + hash = fmt.Sprintf("%x", m.Sum(nil)) if hash != "d7ec5d9d47a4d166091e8d9ebd7ea0aa" { println("BUG gettysburg", hash) println(len(gettysburg)) diff --git a/gcc/testsuite/go.test/test/initsyscall.go b/gcc/testsuite/go.test/test/initsyscall.go index b5e5812b64b..d0c26d2a837 100644 --- a/gcc/testsuite/go.test/test/initsyscall.go +++ b/gcc/testsuite/go.test/test/initsyscall.go @@ -19,9 +19,8 @@ func f() { func init() { go f() - time.Nanoseconds() + time.Now() } func main() { } - diff --git a/libgo/MERGE b/libgo/MERGE index f62ea21e57c..9847f4715a5 100644 --- a/libgo/MERGE +++ b/libgo/MERGE @@ -1,4 +1,4 @@ -b4a91b693374 +0beb796b4ef8 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 9701bada7ce..3db823e8e1a 100644 --- a/libgo/Makefile.am +++ b/libgo/Makefile.am @@ -233,7 +233,6 @@ toolexeclibgoexpdir = $(toolexeclibgodir)/exp toolexeclibgoexp_DATA = \ exp/ebnf.gox \ - exp/gui.gox \ $(exp_inotify_gox) \ exp/norm.gox \ exp/spdy.gox \ @@ -242,11 +241,6 @@ toolexeclibgoexp_DATA = \ exp/terminal.gox \ exp/types.gox -toolexeclibgoexpguidir = $(toolexeclibgoexpdir)/gui - -toolexeclibgoexpgui_DATA = \ - exp/gui/x11.gox - toolexeclibgoexpsqldir = $(toolexeclibgoexpdir)/sql toolexeclibgoexpsql_DATA = \ @@ -447,6 +441,7 @@ runtime_files = \ runtime/go-map-len.c \ runtime/go-map-range.c \ runtime/go-nanotime.c \ + runtime/go-now.c \ runtime/go-new-map.c \ runtime/go-new.c \ runtime/go-panic.c \ @@ -576,6 +571,7 @@ go_hash_files = \ go_html_files = \ go/html/const.go \ go/html/doc.go \ + go/html/doctype.go \ go/html/entity.go \ go/html/escape.go \ go/html/node.go \ @@ -888,7 +884,7 @@ go_time_files = \ go/time/sys_unix.go \ go/time/tick.go \ go/time/time.go \ - go/time/zoneinfo_posix.go \ + go/time/zoneinfo.go \ go/time/zoneinfo_unix.go go_unicode_files = \ @@ -1038,6 +1034,7 @@ go_crypto_twofish_files = \ go_crypto_x509_files = \ go/crypto/x509/cert_pool.go \ go/crypto/x509/pkcs1.go \ + go/crypto/x509/pkcs8.go \ go/crypto/x509/verify.go \ go/crypto/x509/x509.go go_crypto_xtea_files = \ @@ -1135,8 +1132,6 @@ go_encoding_xml_files = \ go_exp_ebnf_files = \ go/exp/ebnf/ebnf.go \ go/exp/ebnf/parser.go -go_exp_gui_files = \ - go/exp/gui/gui.go go_exp_inotify_files = \ go/exp/inotify/inotify_linux.go go_exp_norm_files = \ @@ -1178,10 +1173,6 @@ go_exp_types_files = \ go/exp/types/types.go \ go/exp/types/universe.go -go_exp_gui_x11_files = \ - go/exp/gui/x11/auth.go \ - go/exp/gui/x11/conn.go - go_exp_sql_driver_files = \ go/exp/sql/driver/driver.go \ go/exp/sql/driver/types.go @@ -1415,13 +1406,11 @@ go_text_template_files = \ go/text/template/exec.go \ go/text/template/funcs.go \ go/text/template/helper.go \ - go/text/template/parse.go \ - go/text/template/set.go + go/text/template/template.go go_text_template_parse_files = \ go/text/template/parse/lex.go \ go/text/template/parse/node.go \ - go/text/template/parse/parse.go \ - go/text/template/parse/set.go + go/text/template/parse/parse.go go_sync_atomic_files = \ go/sync/atomic/doc.go @@ -1725,14 +1714,12 @@ libgo_go_objs = \ encoding/pem.lo \ encoding/xml.lo \ exp/ebnf.lo \ - exp/gui.lo \ exp/norm.lo \ exp/spdy.lo \ exp/sql.lo \ exp/ssh.lo \ exp/terminal.lo \ exp/types.lo \ - exp/gui/x11.lo \ exp/sql/driver.lo \ html/template.lo \ go/ast.lo \ @@ -2784,16 +2771,6 @@ exp/ebnf/check: $(CHECK_DEPS) @$(CHECK) .PHONY: exp/ebnf/check -@go_include@ exp/gui.lo.dep -exp/gui.lo.dep: $(go_exp_gui_files) - $(BUILDDEPS) -exp/gui.lo: $(go_exp_gui_files) - $(BUILDPACKAGE) -exp/gui/check: $(CHECK_DEPS) - @$(MKDIR_P) exp/gui - @$(CHECK) -.PHONY: exp/gui/check - @go_include@ exp/norm.lo.dep exp/norm.lo.dep: $(go_exp_norm_files) $(BUILDDEPS) @@ -2854,16 +2831,6 @@ exp/types/check: $(CHECK_DEPS) @$(CHECK) .PHONY: exp/types/check -@go_include@ exp/gui/x11.lo.dep -exp/gui/x11.lo.dep: $(go_exp_gui_x11_files) - $(BUILDDEPS) -exp/gui/x11.lo: $(go_exp_gui_x11_files) - $(BUILDPACKAGE) -exp/gui/x11/check: $(CHECK_DEPS) - @$(MKDIR_P) exp/gui/x11 - @$(CHECK) -.PHONY: exp/gui/x11/check - @go_include@ exp/inotify.lo.dep exp/inotify.lo.dep: $(go_exp_inotify_files) $(BUILDDEPS) @@ -3686,8 +3653,6 @@ encoding/xml.gox: encoding/xml.lo exp/ebnf.gox: exp/ebnf.lo $(BUILDGOX) -exp/gui.gox: exp/gui.lo - $(BUILDGOX) exp/inotify.gox: exp/inotify.lo $(BUILDGOX) exp/norm.gox: exp/norm.lo @@ -3703,9 +3668,6 @@ exp/terminal.gox: exp/terminal.lo exp/types.gox: exp/types.lo $(BUILDGOX) -exp/gui/x11.gox: exp/gui/x11.lo - $(BUILDGOX) - exp/sql/driver.gox: exp/sql/driver.lo $(BUILDGOX) @@ -3950,6 +3912,7 @@ TEST_PACKAGES = \ html/template/check \ go/ast/check \ $(go_build_check_omitted_since_it_calls_6g) \ + go/doc/check \ go/parser/check \ go/printer/check \ go/scanner/check \ diff --git a/libgo/Makefile.in b/libgo/Makefile.in index 3d9ed7c1ca0..6552074a3da 100644 --- a/libgo/Makefile.in +++ b/libgo/Makefile.in @@ -102,7 +102,6 @@ am__installdirs = "$(DESTDIR)$(toolexeclibdir)" \ "$(DESTDIR)$(toolexeclibgodebugdir)" \ "$(DESTDIR)$(toolexeclibgoencodingdir)" \ "$(DESTDIR)$(toolexeclibgoexpdir)" \ - "$(DESTDIR)$(toolexeclibgoexpguidir)" \ "$(DESTDIR)$(toolexeclibgoexpsqldir)" \ "$(DESTDIR)$(toolexeclibgogodir)" \ "$(DESTDIR)$(toolexeclibgohashdir)" \ @@ -161,15 +160,15 @@ am__DEPENDENCIES_2 = bufio/bufio.lo bytes/bytes.lo bytes/index.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/gui.lo exp/norm.lo exp/spdy.lo exp/sql.lo exp/ssh.lo \ - exp/terminal.lo exp/types.lo exp/gui/x11.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 \ - image/ycbcr.lo index/suffixarray.lo io/ioutil.lo log/syslog.lo \ + exp/norm.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 image/ycbcr.lo \ + index/suffixarray.lo io/ioutil.lo log/syslog.lo \ log/syslog/syslog_c.lo math/big.lo math/cmplx.lo math/rand.lo \ mime/mime.lo mime/multipart.lo net/dict.lo net/http.lo \ net/mail.lo net/rpc.lo net/smtp.lo net/textproto.lo net/url.lo \ @@ -200,12 +199,12 @@ am__libgo_la_SOURCES_DIST = runtime/go-append.c runtime/go-assert.c \ runtime/go-interface-val-compare.c runtime/go-make-slice.c \ runtime/go-map-delete.c runtime/go-map-index.c \ runtime/go-map-len.c runtime/go-map-range.c \ - runtime/go-nanotime.c runtime/go-new-map.c runtime/go-new.c \ - runtime/go-panic.c runtime/go-print.c runtime/go-recover.c \ - runtime/go-reflect.c runtime/go-reflect-call.c \ - runtime/go-reflect-map.c runtime/go-rune.c \ - runtime/go-runtime-error.c runtime/go-setenv.c \ - runtime/go-signal.c runtime/go-strcmp.c \ + runtime/go-nanotime.c runtime/go-now.c runtime/go-new-map.c \ + runtime/go-new.c runtime/go-panic.c runtime/go-print.c \ + runtime/go-recover.c runtime/go-reflect.c \ + runtime/go-reflect-call.c runtime/go-reflect-map.c \ + runtime/go-rune.c runtime/go-runtime-error.c \ + runtime/go-setenv.c runtime/go-signal.c runtime/go-strcmp.c \ runtime/go-string-to-byte-array.c \ runtime/go-string-to-int-array.c runtime/go-strplus.c \ runtime/go-strslice.c runtime/go-trampoline.c \ @@ -238,20 +237,20 @@ am__objects_4 = go-append.lo go-assert.lo go-assert-interface.lo \ go-interface-compare.lo go-interface-eface-compare.lo \ go-interface-val-compare.lo go-make-slice.lo go-map-delete.lo \ go-map-index.lo go-map-len.lo go-map-range.lo go-nanotime.lo \ - go-new-map.lo go-new.lo go-panic.lo go-print.lo go-recover.lo \ - go-reflect.lo go-reflect-call.lo go-reflect-map.lo go-rune.lo \ - go-runtime-error.lo go-setenv.lo go-signal.lo go-strcmp.lo \ - go-string-to-byte-array.lo go-string-to-int-array.lo \ - go-strplus.lo go-strslice.lo go-trampoline.lo go-type-eface.lo \ - go-type-error.lo go-type-identity.lo go-type-interface.lo \ - go-type-string.lo go-typedesc-equal.lo go-typestring.lo \ - go-unreflect.lo go-unsafe-new.lo go-unsafe-newarray.lo \ - go-unsafe-pointer.lo go-unwind.lo chan.lo cpuprof.lo \ - $(am__objects_1) mcache.lo mcentral.lo $(am__objects_2) \ - mfinal.lo mfixalloc.lo mgc0.lo mheap.lo msize.lo proc.lo \ - runtime.lo thread.lo yield.lo $(am__objects_3) iface.lo \ - malloc.lo map.lo mprof.lo reflect.lo runtime1.lo sema.lo \ - sigqueue.lo string.lo time.lo + go-now.lo go-new-map.lo go-new.lo go-panic.lo go-print.lo \ + go-recover.lo go-reflect.lo go-reflect-call.lo \ + go-reflect-map.lo go-rune.lo go-runtime-error.lo go-setenv.lo \ + go-signal.lo go-strcmp.lo go-string-to-byte-array.lo \ + go-string-to-int-array.lo go-strplus.lo go-strslice.lo \ + go-trampoline.lo go-type-eface.lo go-type-error.lo \ + go-type-identity.lo go-type-interface.lo go-type-string.lo \ + go-typedesc-equal.lo go-typestring.lo go-unreflect.lo \ + go-unsafe-new.lo go-unsafe-newarray.lo go-unsafe-pointer.lo \ + go-unwind.lo chan.lo cpuprof.lo $(am__objects_1) mcache.lo \ + mcentral.lo $(am__objects_2) mfinal.lo mfixalloc.lo mgc0.lo \ + mheap.lo msize.lo proc.lo runtime.lo thread.lo yield.lo \ + $(am__objects_3) iface.lo malloc.lo map.lo mprof.lo reflect.lo \ + runtime1.lo sema.lo sigqueue.lo string.lo time.lo am_libgo_la_OBJECTS = $(am__objects_4) libgo_la_OBJECTS = $(am_libgo_la_OBJECTS) libgo_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ @@ -290,18 +289,18 @@ DATA = $(toolexeclibgo_DATA) $(toolexeclibgoarchive_DATA) \ $(toolexeclibgocrypto_DATA) $(toolexeclibgocryptoopenpgp_DATA) \ $(toolexeclibgocryptox509_DATA) $(toolexeclibgodebug_DATA) \ $(toolexeclibgoencoding_DATA) $(toolexeclibgoexp_DATA) \ - $(toolexeclibgoexpgui_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) + $(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) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ @@ -690,7 +689,6 @@ toolexeclibgoencoding_DATA = \ toolexeclibgoexpdir = $(toolexeclibgodir)/exp toolexeclibgoexp_DATA = \ exp/ebnf.gox \ - exp/gui.gox \ $(exp_inotify_gox) \ exp/norm.gox \ exp/spdy.gox \ @@ -699,10 +697,6 @@ toolexeclibgoexp_DATA = \ exp/terminal.gox \ exp/types.gox -toolexeclibgoexpguidir = $(toolexeclibgoexpdir)/gui -toolexeclibgoexpgui_DATA = \ - exp/gui/x11.gox - toolexeclibgoexpsqldir = $(toolexeclibgoexpdir)/sql toolexeclibgoexpsql_DATA = \ exp/sql/driver.gox @@ -868,6 +862,7 @@ runtime_files = \ runtime/go-map-len.c \ runtime/go-map-range.c \ runtime/go-nanotime.c \ + runtime/go-now.c \ runtime/go-new-map.c \ runtime/go-new.c \ runtime/go-panic.c \ @@ -960,6 +955,7 @@ go_hash_files = \ go_html_files = \ go/html/const.go \ go/html/doc.go \ + go/html/doctype.go \ go/html/entity.go \ go/html/escape.go \ go/html/node.go \ @@ -1204,7 +1200,7 @@ go_time_files = \ go/time/sys_unix.go \ go/time/tick.go \ go/time/time.go \ - go/time/zoneinfo_posix.go \ + go/time/zoneinfo.go \ go/time/zoneinfo_unix.go go_unicode_files = \ @@ -1377,6 +1373,7 @@ go_crypto_twofish_files = \ go_crypto_x509_files = \ go/crypto/x509/cert_pool.go \ go/crypto/x509/pkcs1.go \ + go/crypto/x509/pkcs8.go \ go/crypto/x509/verify.go \ go/crypto/x509/x509.go @@ -1495,9 +1492,6 @@ go_exp_ebnf_files = \ go/exp/ebnf/ebnf.go \ go/exp/ebnf/parser.go -go_exp_gui_files = \ - go/exp/gui/gui.go - go_exp_inotify_files = \ go/exp/inotify/inotify_linux.go @@ -1545,10 +1539,6 @@ go_exp_types_files = \ go/exp/types/types.go \ go/exp/types/universe.go -go_exp_gui_x11_files = \ - go/exp/gui/x11/auth.go \ - go/exp/gui/x11/conn.go - go_exp_sql_driver_files = \ go/exp/sql/driver/driver.go \ go/exp/sql/driver/types.go @@ -1805,14 +1795,12 @@ go_text_template_files = \ go/text/template/exec.go \ go/text/template/funcs.go \ go/text/template/helper.go \ - go/text/template/parse.go \ - go/text/template/set.go + go/text/template/template.go go_text_template_parse_files = \ go/text/template/parse/lex.go \ go/text/template/parse/node.go \ - go/text/template/parse/parse.go \ - go/text/template/parse/set.go + go/text/template/parse/parse.go go_sync_atomic_files = \ go/sync/atomic/doc.go @@ -2016,14 +2004,12 @@ libgo_go_objs = \ encoding/pem.lo \ encoding/xml.lo \ exp/ebnf.lo \ - exp/gui.lo \ exp/norm.lo \ exp/spdy.lo \ exp/sql.lo \ exp/ssh.lo \ exp/terminal.lo \ exp/types.lo \ - exp/gui/x11.lo \ exp/sql/driver.lo \ html/template.lo \ go/ast.lo \ @@ -2295,6 +2281,7 @@ TEST_PACKAGES = \ html/template/check \ go/ast/check \ $(go_build_check_omitted_since_it_calls_6g) \ + go/doc/check \ go/parser/check \ go/printer/check \ go/scanner/check \ @@ -2511,6 +2498,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-nanotime.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-new-map.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-new.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-now.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-panic.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-print.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-recover.Plo@am__quote@ @@ -2799,6 +2787,13 @@ go-nanotime.lo: runtime/go-nanotime.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-nanotime.lo `test -f 'runtime/go-nanotime.c' || echo '$(srcdir)/'`runtime/go-nanotime.c +go-now.lo: runtime/go-now.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-now.lo -MD -MP -MF $(DEPDIR)/go-now.Tpo -c -o go-now.lo `test -f 'runtime/go-now.c' || echo '$(srcdir)/'`runtime/go-now.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-now.Tpo $(DEPDIR)/go-now.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-now.c' object='go-now.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-now.lo `test -f 'runtime/go-now.c' || echo '$(srcdir)/'`runtime/go-now.c + go-new-map.lo: runtime/go-new-map.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-new-map.lo -MD -MP -MF $(DEPDIR)/go-new-map.Tpo -c -o go-new-map.lo `test -f 'runtime/go-new-map.c' || echo '$(srcdir)/'`runtime/go-new-map.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-new-map.Tpo $(DEPDIR)/go-new-map.Plo @@ -3374,26 +3369,6 @@ uninstall-toolexeclibgoexpDATA: test -n "$$files" || exit 0; \ echo " ( cd '$(DESTDIR)$(toolexeclibgoexpdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(toolexeclibgoexpdir)" && rm -f $$files -install-toolexeclibgoexpguiDATA: $(toolexeclibgoexpgui_DATA) - @$(NORMAL_INSTALL) - test -z "$(toolexeclibgoexpguidir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgoexpguidir)" - @list='$(toolexeclibgoexpgui_DATA)'; test -n "$(toolexeclibgoexpguidir)" || 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)$(toolexeclibgoexpguidir)'"; \ - $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgoexpguidir)" || exit $$?; \ - done - -uninstall-toolexeclibgoexpguiDATA: - @$(NORMAL_UNINSTALL) - @list='$(toolexeclibgoexpgui_DATA)'; test -n "$(toolexeclibgoexpguidir)" || list=; \ - files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ - test -n "$$files" || exit 0; \ - echo " ( cd '$(DESTDIR)$(toolexeclibgoexpguidir)' && rm -f" $$files ")"; \ - cd "$(DESTDIR)$(toolexeclibgoexpguidir)" && rm -f $$files install-toolexeclibgoexpsqlDATA: $(toolexeclibgoexpsql_DATA) @$(NORMAL_INSTALL) test -z "$(toolexeclibgoexpsqldir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgoexpsqldir)" @@ -4171,7 +4146,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)$(toolexeclibgoexpguidir)" "$(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)$(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 \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive @@ -4241,7 +4216,6 @@ install-exec-am: install-multi install-toolexeclibLIBRARIES \ install-toolexeclibgocryptox509DATA \ install-toolexeclibgodebugDATA \ install-toolexeclibgoencodingDATA install-toolexeclibgoexpDATA \ - install-toolexeclibgoexpguiDATA \ install-toolexeclibgoexpsqlDATA install-toolexeclibgogoDATA \ install-toolexeclibgohashDATA install-toolexeclibgohtmlDATA \ install-toolexeclibgoimageDATA install-toolexeclibgoindexDATA \ @@ -4307,7 +4281,6 @@ uninstall-am: uninstall-toolexeclibLIBRARIES \ uninstall-toolexeclibgodebugDATA \ uninstall-toolexeclibgoencodingDATA \ uninstall-toolexeclibgoexpDATA \ - uninstall-toolexeclibgoexpguiDATA \ uninstall-toolexeclibgoexpsqlDATA \ uninstall-toolexeclibgogoDATA uninstall-toolexeclibgohashDATA \ uninstall-toolexeclibgohtmlDATA \ @@ -4355,7 +4328,6 @@ uninstall-am: uninstall-toolexeclibLIBRARIES \ install-toolexeclibgocryptox509DATA \ install-toolexeclibgodebugDATA \ install-toolexeclibgoencodingDATA install-toolexeclibgoexpDATA \ - install-toolexeclibgoexpguiDATA \ install-toolexeclibgoexpsqlDATA install-toolexeclibgogoDATA \ install-toolexeclibgohashDATA install-toolexeclibgohtmlDATA \ install-toolexeclibgoimageDATA install-toolexeclibgoindexDATA \ @@ -4385,7 +4357,6 @@ uninstall-am: uninstall-toolexeclibLIBRARIES \ uninstall-toolexeclibgodebugDATA \ uninstall-toolexeclibgoencodingDATA \ uninstall-toolexeclibgoexpDATA \ - uninstall-toolexeclibgoexpguiDATA \ uninstall-toolexeclibgoexpsqlDATA \ uninstall-toolexeclibgogoDATA uninstall-toolexeclibgohashDATA \ uninstall-toolexeclibgohtmlDATA \ @@ -5383,16 +5354,6 @@ exp/ebnf/check: $(CHECK_DEPS) @$(CHECK) .PHONY: exp/ebnf/check -@go_include@ exp/gui.lo.dep -exp/gui.lo.dep: $(go_exp_gui_files) - $(BUILDDEPS) -exp/gui.lo: $(go_exp_gui_files) - $(BUILDPACKAGE) -exp/gui/check: $(CHECK_DEPS) - @$(MKDIR_P) exp/gui - @$(CHECK) -.PHONY: exp/gui/check - @go_include@ exp/norm.lo.dep exp/norm.lo.dep: $(go_exp_norm_files) $(BUILDDEPS) @@ -5453,16 +5414,6 @@ exp/types/check: $(CHECK_DEPS) @$(CHECK) .PHONY: exp/types/check -@go_include@ exp/gui/x11.lo.dep -exp/gui/x11.lo.dep: $(go_exp_gui_x11_files) - $(BUILDDEPS) -exp/gui/x11.lo: $(go_exp_gui_x11_files) - $(BUILDPACKAGE) -exp/gui/x11/check: $(CHECK_DEPS) - @$(MKDIR_P) exp/gui/x11 - @$(CHECK) -.PHONY: exp/gui/x11/check - @go_include@ exp/inotify.lo.dep exp/inotify.lo.dep: $(go_exp_inotify_files) $(BUILDDEPS) @@ -6280,8 +6231,6 @@ encoding/xml.gox: encoding/xml.lo exp/ebnf.gox: exp/ebnf.lo $(BUILDGOX) -exp/gui.gox: exp/gui.lo - $(BUILDGOX) exp/inotify.gox: exp/inotify.lo $(BUILDGOX) exp/norm.gox: exp/norm.lo @@ -6297,9 +6246,6 @@ exp/terminal.gox: exp/terminal.lo exp/types.gox: exp/types.lo $(BUILDGOX) -exp/gui/x11.gox: exp/gui/x11.lo - $(BUILDGOX) - exp/sql/driver.gox: exp/sql/driver.lo $(BUILDGOX) diff --git a/libgo/go/archive/tar/common.go b/libgo/go/archive/tar/common.go index 67355086a63..fc7a40923cd 100644 --- a/libgo/go/archive/tar/common.go +++ b/libgo/go/archive/tar/common.go @@ -11,41 +11,42 @@ // http://www.gnu.org/software/tar/manual/html_node/Standard.html package tar +import "time" + const ( blockSize = 512 // Types - TypeReg = '0' // regular file. - TypeRegA = '\x00' // regular file. - TypeLink = '1' // hard link. - TypeSymlink = '2' // symbolic link. - TypeChar = '3' // character device node. - TypeBlock = '4' // block device node. - TypeDir = '5' // directory. - TypeFifo = '6' // fifo node. - TypeCont = '7' // reserved. - TypeXHeader = 'x' // extended header. - TypeXGlobalHeader = 'g' // global extended header. + TypeReg = '0' // regular file + TypeRegA = '\x00' // regular file + TypeLink = '1' // hard link + TypeSymlink = '2' // symbolic link + TypeChar = '3' // character device node + TypeBlock = '4' // block device node + TypeDir = '5' // directory + TypeFifo = '6' // fifo node + TypeCont = '7' // reserved + TypeXHeader = 'x' // extended header + TypeXGlobalHeader = 'g' // global extended header ) // A Header represents a single header in a tar archive. // Some fields may not be populated. type Header struct { - Name string // name of header file entry. - Mode int64 // permission and mode bits. - Uid int // user id of owner. - Gid int // group id of owner. - Size int64 // length in bytes. - Mtime int64 // modified time; seconds since epoch. - Typeflag byte // type of header entry. - Linkname string // target name of link. - Uname string // user name of owner. - Gname string // group name of owner. - Devmajor int64 // major number of character or block device. - Devminor int64 // minor number of character or block device. - Atime int64 // access time; seconds since epoch. - Ctime int64 // status change time; seconds since epoch. - + Name string // name of header file entry + Mode int64 // permission and mode bits + Uid int // user id of owner + Gid int // group id of owner + Size int64 // length in bytes + ModTime time.Time // modified time + Typeflag byte // type of header entry + Linkname string // target name of link + Uname string // user name of owner + Gname string // group name of owner + Devmajor int64 // major number of character or block device + Devminor int64 // minor number of character or block device + AccessTime time.Time // access time + ChangeTime time.Time // status change time } var zeroBlock = make([]byte, blockSize) diff --git a/libgo/go/archive/tar/reader.go b/libgo/go/archive/tar/reader.go index facba2cc7a3..76955e2ec03 100644 --- a/libgo/go/archive/tar/reader.go +++ b/libgo/go/archive/tar/reader.go @@ -14,6 +14,7 @@ import ( "io/ioutil" "os" "strconv" + "time" ) var ( @@ -141,7 +142,7 @@ func (tr *Reader) readHeader() *Header { hdr.Uid = int(tr.octal(s.next(8))) hdr.Gid = int(tr.octal(s.next(8))) hdr.Size = tr.octal(s.next(12)) - hdr.Mtime = tr.octal(s.next(12)) + hdr.ModTime = time.Unix(tr.octal(s.next(12)), 0) s.next(8) // chksum hdr.Typeflag = s.next(1)[0] hdr.Linkname = cString(s.next(100)) @@ -178,8 +179,8 @@ func (tr *Reader) readHeader() *Header { prefix = cString(s.next(155)) case "star": prefix = cString(s.next(131)) - hdr.Atime = tr.octal(s.next(12)) - hdr.Ctime = tr.octal(s.next(12)) + hdr.AccessTime = time.Unix(tr.octal(s.next(12)), 0) + hdr.ChangeTime = time.Unix(tr.octal(s.next(12)), 0) } if len(prefix) > 0 { hdr.Name = prefix + "/" + hdr.Name diff --git a/libgo/go/archive/tar/reader_test.go b/libgo/go/archive/tar/reader_test.go index 00eea6b62d7..5ca4212ae7b 100644 --- a/libgo/go/archive/tar/reader_test.go +++ b/libgo/go/archive/tar/reader_test.go @@ -12,6 +12,7 @@ import ( "os" "reflect" "testing" + "time" ) type untarTest struct { @@ -29,7 +30,7 @@ var gnuTarTest = &untarTest{ Uid: 73025, Gid: 5000, Size: 5, - Mtime: 1244428340, + ModTime: time.Unix(1244428340, 0), Typeflag: '0', Uname: "dsymonds", Gname: "eng", @@ -40,7 +41,7 @@ var gnuTarTest = &untarTest{ Uid: 73025, Gid: 5000, Size: 11, - Mtime: 1244436044, + ModTime: time.Unix(1244436044, 0), Typeflag: '0', Uname: "dsymonds", Gname: "eng", @@ -58,30 +59,30 @@ var untarTests = []*untarTest{ file: "testdata/star.tar", headers: []*Header{ &Header{ - Name: "small.txt", - Mode: 0640, - Uid: 73025, - Gid: 5000, - Size: 5, - Mtime: 1244592783, - Typeflag: '0', - Uname: "dsymonds", - Gname: "eng", - Atime: 1244592783, - Ctime: 1244592783, + Name: "small.txt", + Mode: 0640, + Uid: 73025, + Gid: 5000, + Size: 5, + ModTime: time.Unix(1244592783, 0), + Typeflag: '0', + Uname: "dsymonds", + Gname: "eng", + AccessTime: time.Unix(1244592783, 0), + ChangeTime: time.Unix(1244592783, 0), }, &Header{ - Name: "small2.txt", - Mode: 0640, - Uid: 73025, - Gid: 5000, - Size: 11, - Mtime: 1244592783, - Typeflag: '0', - Uname: "dsymonds", - Gname: "eng", - Atime: 1244592783, - Ctime: 1244592783, + Name: "small2.txt", + Mode: 0640, + Uid: 73025, + Gid: 5000, + Size: 11, + ModTime: time.Unix(1244592783, 0), + Typeflag: '0', + Uname: "dsymonds", + Gname: "eng", + AccessTime: time.Unix(1244592783, 0), + ChangeTime: time.Unix(1244592783, 0), }, }, }, @@ -94,7 +95,7 @@ var untarTests = []*untarTest{ Uid: 73025, Gid: 5000, Size: 5, - Mtime: 1244593104, + ModTime: time.Unix(1244593104, 0), Typeflag: '\x00', }, &Header{ @@ -103,7 +104,7 @@ var untarTests = []*untarTest{ Uid: 73025, Gid: 5000, Size: 11, - Mtime: 1244593104, + ModTime: time.Unix(1244593104, 0), Typeflag: '\x00', }, }, @@ -221,7 +222,7 @@ func TestIncrementalRead(t *testing.T) { h.Write(rdbuf[0:nr]) } // verify checksum - have := fmt.Sprintf("%x", h.Sum()) + have := fmt.Sprintf("%x", h.Sum(nil)) want := cksums[nread] if want != have { t.Errorf("Bad checksum on file %s:\nhave %+v\nwant %+v", hdr.Name, have, want) diff --git a/libgo/go/archive/tar/writer.go b/libgo/go/archive/tar/writer.go index 222df90782c..b9310b3f189 100644 --- a/libgo/go/archive/tar/writer.go +++ b/libgo/go/archive/tar/writer.go @@ -127,19 +127,19 @@ func (tw *Writer) WriteHeader(hdr *Header) error { // TODO(dsymonds): handle names longer than 100 chars copy(s.next(100), []byte(hdr.Name)) - tw.octal(s.next(8), hdr.Mode) // 100:108 - tw.numeric(s.next(8), int64(hdr.Uid)) // 108:116 - tw.numeric(s.next(8), int64(hdr.Gid)) // 116:124 - tw.numeric(s.next(12), hdr.Size) // 124:136 - tw.numeric(s.next(12), hdr.Mtime) // 136:148 - s.next(8) // chksum (148:156) - s.next(1)[0] = hdr.Typeflag // 156:157 - tw.cString(s.next(100), hdr.Linkname) // linkname (157:257) - copy(s.next(8), []byte("ustar\x0000")) // 257:265 - tw.cString(s.next(32), hdr.Uname) // 265:297 - tw.cString(s.next(32), hdr.Gname) // 297:329 - tw.numeric(s.next(8), hdr.Devmajor) // 329:337 - tw.numeric(s.next(8), hdr.Devminor) // 337:345 + tw.octal(s.next(8), hdr.Mode) // 100:108 + tw.numeric(s.next(8), int64(hdr.Uid)) // 108:116 + tw.numeric(s.next(8), int64(hdr.Gid)) // 116:124 + tw.numeric(s.next(12), hdr.Size) // 124:136 + tw.numeric(s.next(12), hdr.ModTime.Unix()) // 136:148 + s.next(8) // chksum (148:156) + s.next(1)[0] = hdr.Typeflag // 156:157 + tw.cString(s.next(100), hdr.Linkname) // linkname (157:257) + copy(s.next(8), []byte("ustar\x0000")) // 257:265 + tw.cString(s.next(32), hdr.Uname) // 265:297 + tw.cString(s.next(32), hdr.Gname) // 297:329 + tw.numeric(s.next(8), hdr.Devmajor) // 329:337 + tw.numeric(s.next(8), hdr.Devminor) // 337:345 // Use the GNU magic instead of POSIX magic if we used any GNU extensions. if tw.usedBinary { diff --git a/libgo/go/archive/tar/writer_test.go b/libgo/go/archive/tar/writer_test.go index 6cc93868820..8d7ed32d32e 100644 --- a/libgo/go/archive/tar/writer_test.go +++ b/libgo/go/archive/tar/writer_test.go @@ -11,6 +11,7 @@ import ( "io/ioutil" "testing" "testing/iotest" + "time" ) type writerTestEntry struct { @@ -38,7 +39,7 @@ var writerTests = []*writerTest{ Uid: 73025, Gid: 5000, Size: 5, - Mtime: 1246508266, + ModTime: time.Unix(1246508266, 0), Typeflag: '0', Uname: "dsymonds", Gname: "eng", @@ -52,7 +53,7 @@ var writerTests = []*writerTest{ Uid: 73025, Gid: 5000, Size: 11, - Mtime: 1245217492, + ModTime: time.Unix(1245217492, 0), Typeflag: '0', Uname: "dsymonds", Gname: "eng", @@ -66,7 +67,7 @@ var writerTests = []*writerTest{ Uid: 1000, Gid: 1000, Size: 0, - Mtime: 1314603082, + ModTime: time.Unix(1314603082, 0), Typeflag: '2', Linkname: "small.txt", Uname: "strings", @@ -89,7 +90,7 @@ var writerTests = []*writerTest{ Uid: 73025, Gid: 5000, Size: 16 << 30, - Mtime: 1254699560, + ModTime: time.Unix(1254699560, 0), Typeflag: '0', Uname: "dsymonds", Gname: "eng", diff --git a/libgo/go/archive/zip/reader.go b/libgo/go/archive/zip/reader.go index cfbe5498a15..4365009a308 100644 --- a/libgo/go/archive/zip/reader.go +++ b/libgo/go/archive/zip/reader.go @@ -56,7 +56,7 @@ func OpenReader(name string) (*ReadCloser, error) { return nil, err } r := new(ReadCloser) - if err := r.init(f, fi.Size); err != nil { + if err := r.init(f, fi.Size()); err != nil { f.Close() return nil, err } diff --git a/libgo/go/archive/zip/reader_test.go b/libgo/go/archive/zip/reader_test.go index ca0b04e2bba..8c0ecaa4386 100644 --- a/libgo/go/archive/zip/reader_test.go +++ b/libgo/go/archive/zip/reader_test.go @@ -164,8 +164,8 @@ func readTestFile(t *testing.T, ft ZipTestFile, f *File) { t.Error(err) return } - if got, want := f.Mtime_ns()/1e9, mtime.Seconds(); got != want { - t.Errorf("%s: mtime=%s (%d); want %s (%d)", f.Name, time.SecondsToUTC(got), got, mtime, want) + if ft := f.ModTime(); !ft.Equal(mtime) { + t.Errorf("%s: mtime=%s, want %s", f.Name, ft, mtime) } testFileMode(t, f, ft.Mode) diff --git a/libgo/go/archive/zip/struct.go b/libgo/go/archive/zip/struct.go index b862b5a6acb..43c04bb27b2 100644 --- a/libgo/go/archive/zip/struct.go +++ b/libgo/go/archive/zip/struct.go @@ -11,8 +11,10 @@ This package does not support ZIP64 or disk spanning. */ package zip -import "errors" -import "time" +import ( + "errors" + "time" +) // Compression methods. const ( @@ -74,24 +76,26 @@ func recoverError(errp *error) { // The resolution is 2s. // See: http://msdn.microsoft.com/en-us/library/ms724247(v=VS.85).aspx func msDosTimeToTime(dosDate, dosTime uint16) time.Time { - return time.Time{ + return time.Date( // date bits 0-4: day of month; 5-8: month; 9-15: years since 1980 - Year: int64(dosDate>>9 + 1980), - Month: int(dosDate >> 5 & 0xf), - Day: int(dosDate & 0x1f), + int(dosDate>>9+1980), + time.Month(dosDate>>5&0xf), + int(dosDate&0x1f), // time bits 0-4: second/2; 5-10: minute; 11-15: hour - Hour: int(dosTime >> 11), - Minute: int(dosTime >> 5 & 0x3f), - Second: int(dosTime & 0x1f * 2), - } + int(dosTime>>11), + int(dosTime>>5&0x3f), + int(dosTime&0x1f*2), + 0, // nanoseconds + + time.UTC, + ) } -// Mtime_ns returns the modified time in ns since epoch. +// ModTime returns the modification time. // The resolution is 2s. -func (h *FileHeader) Mtime_ns() int64 { - t := msDosTimeToTime(h.ModifiedDate, h.ModifiedTime) - return t.Seconds() * 1e9 +func (h *FileHeader) ModTime() time.Time { + return msDosTimeToTime(h.ModifiedDate, h.ModifiedTime) } // Mode returns the permission and mode bits for the FileHeader. diff --git a/libgo/go/bytes/bytes_test.go b/libgo/go/bytes/bytes_test.go index 21a1a4f5808..829ef05319c 100644 --- a/libgo/go/bytes/bytes_test.go +++ b/libgo/go/bytes/bytes_test.go @@ -702,7 +702,7 @@ func TestTrim(t *testing.T) { case "TrimRight": f = TrimRight default: - t.Error("Undefined trim function %s", name) + t.Errorf("Undefined trim function %s", name) } actual := string(f([]byte(tc.in), tc.cutset)) if actual != tc.out { diff --git a/libgo/go/compress/gzip/gunzip.go b/libgo/go/compress/gzip/gunzip.go index a23e515e0e0..7c78b9e366d 100644 --- a/libgo/go/compress/gzip/gunzip.go +++ b/libgo/go/compress/gzip/gunzip.go @@ -13,6 +13,7 @@ import ( "hash" "hash/crc32" "io" + "time" ) // BUG(nigeltao): Comments and Names don't properly map UTF-8 character codes outside of @@ -42,11 +43,11 @@ var ChecksumError = errors.New("gzip checksum error") // The gzip file stores a header giving metadata about the compressed file. // That header is exposed as the fields of the Compressor and Decompressor structs. type Header struct { - Comment string // comment - Extra []byte // "extra data" - Mtime uint32 // modification time (seconds since January 1, 1970) - Name string // file name - OS byte // operating system type + Comment string // comment + Extra []byte // "extra data" + ModTime time.Time // modification time + Name string // file name + OS byte // operating system type } // An Decompressor is an io.Reader that can be read to retrieve @@ -130,7 +131,7 @@ func (z *Decompressor) readHeader(save bool) error { } z.flg = z.buf[3] if save { - z.Mtime = get4(z.buf[4:8]) + z.ModTime = time.Unix(int64(get4(z.buf[4:8])), 0) // z.buf[8] is xfl, ignored z.OS = z.buf[9] } diff --git a/libgo/go/compress/gzip/gzip.go b/libgo/go/compress/gzip/gzip.go index 94b0f1f85e2..07b91b66823 100644 --- a/libgo/go/compress/gzip/gzip.go +++ b/libgo/go/compress/gzip/gzip.go @@ -122,7 +122,7 @@ func (z *Compressor) Write(p []byte) (int, error) { if z.Comment != "" { z.buf[3] |= 0x10 } - put4(z.buf[4:8], z.Mtime) + put4(z.buf[4:8], uint32(z.ModTime.Unix())) if z.level == BestCompression { z.buf[8] = 2 } else if z.level == BestSpeed { diff --git a/libgo/go/compress/gzip/gzip_test.go b/libgo/go/compress/gzip/gzip_test.go index 121e627e6b2..815825be999 100644 --- a/libgo/go/compress/gzip/gzip_test.go +++ b/libgo/go/compress/gzip/gzip_test.go @@ -8,6 +8,7 @@ import ( "io" "io/ioutil" "testing" + "time" ) // pipe creates two ends of a pipe that gzip and gunzip, and runs dfunc at the @@ -53,7 +54,7 @@ func TestWriter(t *testing.T) { func(compressor *Compressor) { compressor.Comment = "comment" compressor.Extra = []byte("extra") - compressor.Mtime = 1e8 + compressor.ModTime = time.Unix(1e8, 0) compressor.Name = "name" _, err := compressor.Write([]byte("payload")) if err != nil { @@ -74,8 +75,8 @@ func TestWriter(t *testing.T) { if string(decompressor.Extra) != "extra" { t.Fatalf("extra is %q, want %q", decompressor.Extra, "extra") } - if decompressor.Mtime != 1e8 { - t.Fatalf("mtime is %d, want %d", decompressor.Mtime, uint32(1e8)) + if decompressor.ModTime.Unix() != 1e8 { + t.Fatalf("mtime is %d, want %d", decompressor.ModTime.Unix(), uint32(1e8)) } if decompressor.Name != "name" { t.Fatalf("name is %q, want %q", decompressor.Name, "name") diff --git a/libgo/go/crypto/bcrypt/bcrypt.go b/libgo/go/crypto/bcrypt/bcrypt.go index 97401356228..362b2eb53cb 100644 --- a/libgo/go/crypto/bcrypt/bcrypt.go +++ b/libgo/go/crypto/bcrypt/bcrypt.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package bcrypt implements Provos and Mazières's bcrypt adapative hashing +// Package bcrypt implements Provos and Mazières's bcrypt adaptive hashing // algorithm. See http://www.usenix.org/event/usenix99/provos/provos.pdf package bcrypt diff --git a/libgo/go/crypto/ecdsa/ecdsa_test.go b/libgo/go/crypto/ecdsa/ecdsa_test.go index 22360b5708c..45433e10203 100644 --- a/libgo/go/crypto/ecdsa/ecdsa_test.go +++ b/libgo/go/crypto/ecdsa/ecdsa_test.go @@ -214,7 +214,7 @@ func TestVectors(t *testing.T) { msg, _ := hex.DecodeString(test.msg) sha.Reset() sha.Write(msg) - hashed := sha.Sum() + hashed := sha.Sum(nil) r := fromHex(test.r) s := fromHex(test.s) if Verify(&pub, hashed, r, s) != test.ok { diff --git a/libgo/go/crypto/hmac/hmac.go b/libgo/go/crypto/hmac/hmac.go index 6a17bbd44fa..deaceafb260 100644 --- a/libgo/go/crypto/hmac/hmac.go +++ b/libgo/go/crypto/hmac/hmac.go @@ -48,15 +48,15 @@ func (h *hmac) tmpPad(xor byte) { } } -func (h *hmac) Sum() []byte { - sum := h.inner.Sum() +func (h *hmac) Sum(in []byte) []byte { + sum := h.inner.Sum(nil) h.tmpPad(0x5c) for i, b := range sum { h.tmp[padSize+i] = b } h.outer.Reset() h.outer.Write(h.tmp) - return h.outer.Sum() + return h.outer.Sum(in) } func (h *hmac) Write(p []byte) (n int, err error) { @@ -81,7 +81,7 @@ func New(h func() hash.Hash, key []byte) hash.Hash { if len(key) > padSize { // If key is too big, hash it. hm.outer.Write(key) - key = hm.outer.Sum() + key = hm.outer.Sum(nil) } hm.key = make([]byte, len(key)) copy(hm.key, key) diff --git a/libgo/go/crypto/hmac/hmac_test.go b/libgo/go/crypto/hmac/hmac_test.go index 03431c92f75..eac254b9d19 100644 --- a/libgo/go/crypto/hmac/hmac_test.go +++ b/libgo/go/crypto/hmac/hmac_test.go @@ -192,7 +192,7 @@ func TestHMAC(t *testing.T) { // Repetitive Sum() calls should return the same value for k := 0; k < 2; k++ { - sum := fmt.Sprintf("%x", h.Sum()) + sum := fmt.Sprintf("%x", h.Sum(nil)) if sum != tt.out { t.Errorf("test %d.%d.%d: have %s want %s\n", i, j, k, sum, tt.out) } diff --git a/libgo/go/crypto/md4/md4.go b/libgo/go/crypto/md4/md4.go index f21cc51a21a..e51e8bee50c 100644 --- a/libgo/go/crypto/md4/md4.go +++ b/libgo/go/crypto/md4/md4.go @@ -77,7 +77,7 @@ func (d *digest) Write(p []byte) (nn int, err error) { return } -func (d0 *digest) Sum() []byte { +func (d0 *digest) Sum(in []byte) []byte { // Make a copy of d0, so that caller can keep writing and summing. d := new(digest) *d = *d0 @@ -103,14 +103,11 @@ func (d0 *digest) Sum() []byte { panic("d.nx != 0") } - p := make([]byte, 16) - j := 0 for _, s := range d.s { - p[j+0] = byte(s >> 0) - p[j+1] = byte(s >> 8) - p[j+2] = byte(s >> 16) - p[j+3] = byte(s >> 24) - j += 4 + in = append(in, byte(s>>0)) + in = append(in, byte(s>>8)) + in = append(in, byte(s>>16)) + in = append(in, byte(s>>24)) } - return p + return in } diff --git a/libgo/go/crypto/md4/md4_test.go b/libgo/go/crypto/md4/md4_test.go index 721bd4cbcc8..b56edd7875d 100644 --- a/libgo/go/crypto/md4/md4_test.go +++ b/libgo/go/crypto/md4/md4_test.go @@ -58,10 +58,10 @@ func TestGolden(t *testing.T) { io.WriteString(c, g.in) } else { io.WriteString(c, g.in[0:len(g.in)/2]) - c.Sum() + c.Sum(nil) io.WriteString(c, g.in[len(g.in)/2:]) } - s := fmt.Sprintf("%x", c.Sum()) + s := fmt.Sprintf("%x", c.Sum(nil)) if s != g.out { t.Fatalf("md4[%d](%s) = %s want %s", j, g.in, s, g.out) } diff --git a/libgo/go/crypto/md5/md5.go b/libgo/go/crypto/md5/md5.go index 20f3a1b6f75..182cfb85370 100644 --- a/libgo/go/crypto/md5/md5.go +++ b/libgo/go/crypto/md5/md5.go @@ -77,7 +77,7 @@ func (d *digest) Write(p []byte) (nn int, err error) { return } -func (d0 *digest) Sum() []byte { +func (d0 *digest) Sum(in []byte) []byte { // Make a copy of d0 so that caller can keep writing and summing. d := new(digest) *d = *d0 @@ -103,14 +103,11 @@ func (d0 *digest) Sum() []byte { panic("d.nx != 0") } - p := make([]byte, 16) - j := 0 for _, s := range d.s { - p[j+0] = byte(s >> 0) - p[j+1] = byte(s >> 8) - p[j+2] = byte(s >> 16) - p[j+3] = byte(s >> 24) - j += 4 + in = append(in, byte(s>>0)) + in = append(in, byte(s>>8)) + in = append(in, byte(s>>16)) + in = append(in, byte(s>>24)) } - return p + return in } diff --git a/libgo/go/crypto/md5/md5_test.go b/libgo/go/crypto/md5/md5_test.go index 857002b7013..b15e4668c32 100644 --- a/libgo/go/crypto/md5/md5_test.go +++ b/libgo/go/crypto/md5/md5_test.go @@ -58,10 +58,10 @@ func TestGolden(t *testing.T) { io.WriteString(c, g.in) } else { io.WriteString(c, g.in[0:len(g.in)/2]) - c.Sum() + c.Sum(nil) io.WriteString(c, g.in[len(g.in)/2:]) } - s := fmt.Sprintf("%x", c.Sum()) + s := fmt.Sprintf("%x", c.Sum(nil)) if s != g.out { t.Fatalf("md5[%d](%s) = %s want %s", j, g.in, s, g.out) } diff --git a/libgo/go/crypto/ocsp/ocsp.go b/libgo/go/crypto/ocsp/ocsp.go index a04b5bd7135..b9dfdf94e31 100644 --- a/libgo/go/crypto/ocsp/ocsp.go +++ b/libgo/go/crypto/ocsp/ocsp.go @@ -61,7 +61,7 @@ type responseData struct { Version int `asn1:"optional,default:1,explicit,tag:0"` RequestorName pkix.RDNSequence `asn1:"optional,explicit,tag:1"` KeyHash []byte `asn1:"optional,explicit,tag:2"` - ProducedAt *time.Time + ProducedAt time.Time Responses []singleResponse } @@ -70,12 +70,12 @@ type singleResponse struct { Good asn1.Flag `asn1:"explicit,tag:0,optional"` Revoked revokedInfo `asn1:"explicit,tag:1,optional"` Unknown asn1.Flag `asn1:"explicit,tag:2,optional"` - ThisUpdate *time.Time - NextUpdate *time.Time `asn1:"explicit,tag:0,optional"` + ThisUpdate time.Time + NextUpdate time.Time `asn1:"explicit,tag:0,optional"` } type revokedInfo struct { - RevocationTime *time.Time + RevocationTime time.Time Reason int `asn1:"explicit,tag:0,optional"` } @@ -97,7 +97,7 @@ type Response struct { // Status is one of {Good, Revoked, Unknown, ServerFailed} Status int SerialNumber []byte - ProducedAt, ThisUpdate, NextUpdate, RevokedAt *time.Time + ProducedAt, ThisUpdate, NextUpdate, RevokedAt time.Time RevocationReason int Certificate *x509.Certificate } @@ -161,7 +161,7 @@ func ParseResponse(bytes []byte) (*Response, error) { pub := ret.Certificate.PublicKey.(*rsa.PublicKey) h.Write(basicResp.TBSResponseData.Raw) - digest := h.Sum() + digest := h.Sum(nil) signature := basicResp.Signature.RightAlign() if rsa.VerifyPKCS1v15(pub, hashType, digest, signature) != nil { diff --git a/libgo/go/crypto/ocsp/ocsp_test.go b/libgo/go/crypto/ocsp/ocsp_test.go index 7be37211c10..bacca558b48 100644 --- a/libgo/go/crypto/ocsp/ocsp_test.go +++ b/libgo/go/crypto/ocsp/ocsp_test.go @@ -15,7 +15,13 @@ func TestOCSPDecode(t *testing.T) { t.Error(err) } - expected := Response{Status: 0, SerialNumber: []byte{0x1, 0xd0, 0xfa}, RevocationReason: 0, ThisUpdate: &time.Time{Year: 2010, Month: 7, Day: 7, Hour: 15, Minute: 1, Second: 5, ZoneOffset: 0, Zone: "UTC"}, NextUpdate: &time.Time{Year: 2010, Month: 7, Day: 7, Hour: 18, Minute: 35, Second: 17, ZoneOffset: 0, Zone: "UTC"}} + expected := Response{ + Status: 0, + SerialNumber: []byte{0x1, 0xd0, 0xfa}, + RevocationReason: 0, + ThisUpdate: time.Date(2010, 7, 7, 15, 1, 5, 0, time.UTC), + NextUpdate: time.Date(2010, 7, 7, 18, 35, 17, 0, time.UTC), + } if !reflect.DeepEqual(resp.ThisUpdate, resp.ThisUpdate) { t.Errorf("resp.ThisUpdate: got %d, want %d", resp.ThisUpdate, expected.ThisUpdate) diff --git a/libgo/go/crypto/openpgp/canonical_text.go b/libgo/go/crypto/openpgp/canonical_text.go index fe4557aafc1..98cee5e75ae 100644 --- a/libgo/go/crypto/openpgp/canonical_text.go +++ b/libgo/go/crypto/openpgp/canonical_text.go @@ -41,8 +41,8 @@ func (cth *canonicalTextHash) Write(buf []byte) (int, error) { return len(buf), nil } -func (cth *canonicalTextHash) Sum() []byte { - return cth.h.Sum() +func (cth *canonicalTextHash) Sum(in []byte) []byte { + return cth.h.Sum(in) } func (cth *canonicalTextHash) Reset() { diff --git a/libgo/go/crypto/openpgp/canonical_text_test.go b/libgo/go/crypto/openpgp/canonical_text_test.go index ae54f8c83ee..841475f80c0 100644 --- a/libgo/go/crypto/openpgp/canonical_text_test.go +++ b/libgo/go/crypto/openpgp/canonical_text_test.go @@ -17,8 +17,8 @@ func (r recordingHash) Write(b []byte) (n int, err error) { return r.buf.Write(b) } -func (r recordingHash) Sum() []byte { - return r.buf.Bytes() +func (r recordingHash) Sum(in []byte) []byte { + return append(in, r.buf.Bytes()...) } func (r recordingHash) Reset() { @@ -33,7 +33,7 @@ func testCanonicalText(t *testing.T, input, expected string) { r := recordingHash{bytes.NewBuffer(nil)} c := NewCanonicalTextHash(r) c.Write([]byte(input)) - result := c.Sum() + result := c.Sum(nil) if expected != string(result) { t.Errorf("input: %x got: %x want: %x", input, result, expected) } diff --git a/libgo/go/crypto/openpgp/keys.go b/libgo/go/crypto/openpgp/keys.go index b705d226e1f..df39970c0b6 100644 --- a/libgo/go/crypto/openpgp/keys.go +++ b/libgo/go/crypto/openpgp/keys.go @@ -381,7 +381,7 @@ const defaultRSAKeyBits = 2048 // NewEntity returns an Entity that contains a fresh RSA/RSA keypair with a // single identity composed of the given full name, comment and email, any of // which may be empty but must not contain any of "()<>\x00". -func NewEntity(rand io.Reader, currentTimeSecs int64, name, comment, email string) (*Entity, error) { +func NewEntity(rand io.Reader, currentTime time.Time, name, comment, email string) (*Entity, error) { uid := packet.NewUserId(name, comment, email) if uid == nil { return nil, error_.InvalidArgumentError("user id field contained invalid characters") @@ -395,11 +395,9 @@ func NewEntity(rand io.Reader, currentTimeSecs int64, name, comment, email strin return nil, err } - t := uint32(currentTimeSecs) - e := &Entity{ - PrimaryKey: packet.NewRSAPublicKey(t, &signingPriv.PublicKey, false /* not a subkey */ ), - PrivateKey: packet.NewRSAPrivateKey(t, signingPriv, false /* not a subkey */ ), + PrimaryKey: packet.NewRSAPublicKey(currentTime, &signingPriv.PublicKey, false /* not a subkey */ ), + PrivateKey: packet.NewRSAPrivateKey(currentTime, signingPriv, false /* not a subkey */ ), Identities: make(map[string]*Identity), } isPrimaryId := true @@ -407,7 +405,7 @@ func NewEntity(rand io.Reader, currentTimeSecs int64, name, comment, email strin Name: uid.Name, UserId: uid, SelfSignature: &packet.Signature{ - CreationTime: t, + CreationTime: currentTime, SigType: packet.SigTypePositiveCert, PubKeyAlgo: packet.PubKeyAlgoRSA, Hash: crypto.SHA256, @@ -421,10 +419,10 @@ func NewEntity(rand io.Reader, currentTimeSecs int64, name, comment, email strin e.Subkeys = make([]Subkey, 1) e.Subkeys[0] = Subkey{ - PublicKey: packet.NewRSAPublicKey(t, &encryptingPriv.PublicKey, true /* is a subkey */ ), - PrivateKey: packet.NewRSAPrivateKey(t, encryptingPriv, true /* is a subkey */ ), + PublicKey: packet.NewRSAPublicKey(currentTime, &encryptingPriv.PublicKey, true /* is a subkey */ ), + PrivateKey: packet.NewRSAPrivateKey(currentTime, encryptingPriv, true /* is a subkey */ ), Sig: &packet.Signature{ - CreationTime: t, + CreationTime: currentTime, SigType: packet.SigTypeSubkeyBinding, PubKeyAlgo: packet.PubKeyAlgoRSA, Hash: crypto.SHA256, @@ -533,7 +531,7 @@ func (e *Entity) SignIdentity(identity string, signer *Entity) error { SigType: packet.SigTypeGenericCert, PubKeyAlgo: signer.PrivateKey.PubKeyAlgo, Hash: crypto.SHA256, - CreationTime: uint32(time.Seconds()), + CreationTime: time.Now(), IssuerKeyId: &signer.PrivateKey.KeyId, } if err := sig.SignKey(e.PrimaryKey, signer.PrivateKey); err != nil { diff --git a/libgo/go/crypto/openpgp/packet/private_key.go b/libgo/go/crypto/openpgp/packet/private_key.go index c0ff82b4135..d67e9688617 100644 --- a/libgo/go/crypto/openpgp/packet/private_key.go +++ b/libgo/go/crypto/openpgp/packet/private_key.go @@ -17,6 +17,7 @@ import ( "io/ioutil" "math/big" "strconv" + "time" ) // PrivateKey represents a possibly encrypted private key. See RFC 4880, @@ -32,9 +33,9 @@ type PrivateKey struct { iv []byte } -func NewRSAPrivateKey(currentTimeSecs uint32, priv *rsa.PrivateKey, isSubkey bool) *PrivateKey { +func NewRSAPrivateKey(currentTime time.Time, priv *rsa.PrivateKey, isSubkey bool) *PrivateKey { pk := new(PrivateKey) - pk.PublicKey = *NewRSAPublicKey(currentTimeSecs, &priv.PublicKey, isSubkey) + pk.PublicKey = *NewRSAPublicKey(currentTime, &priv.PublicKey, isSubkey) pk.PrivateKey = priv return pk } @@ -99,13 +100,9 @@ func (pk *PrivateKey) parse(r io.Reader) (err error) { } func mod64kHash(d []byte) uint16 { - h := uint16(0) - for i := 0; i < len(d); i += 2 { - v := uint16(d[i]) << 8 - if i+1 < len(d) { - v += uint16(d[i+1]) - } - h += v + var h uint16 + for _, b := range d { + h += uint16(b) } return h } @@ -195,7 +192,7 @@ func (pk *PrivateKey) Decrypt(passphrase []byte) error { } h := sha1.New() h.Write(data[:len(data)-sha1.Size]) - sum := h.Sum() + sum := h.Sum(nil) if !bytes.Equal(sum, data[len(data)-sha1.Size:]) { return error_.StructuralError("private key checksum failure") } diff --git a/libgo/go/crypto/openpgp/packet/private_key_test.go b/libgo/go/crypto/openpgp/packet/private_key_test.go index 60eebaa6b09..35d8951a86b 100644 --- a/libgo/go/crypto/openpgp/packet/private_key_test.go +++ b/libgo/go/crypto/openpgp/packet/private_key_test.go @@ -6,19 +6,20 @@ package packet import ( "testing" + "time" ) var privateKeyTests = []struct { privateKeyHex string - creationTime uint32 + creationTime time.Time }{ { privKeyRSAHex, - 0x4cc349a8, + time.Unix(0x4cc349a8, 0), }, { privKeyElGamalHex, - 0x4df9ee1a, + time.Unix(0x4df9ee1a, 0), }, } @@ -43,7 +44,7 @@ func TestPrivateKeyRead(t *testing.T) { continue } - if privKey.CreationTime != test.creationTime || privKey.Encrypted { + if !privKey.CreationTime.Equal(test.creationTime) || privKey.Encrypted { t.Errorf("#%d: bad result, got: %#v", i, privKey) } } diff --git a/libgo/go/crypto/openpgp/packet/public_key.go b/libgo/go/crypto/openpgp/packet/public_key.go index 7d71dc49a7b..9aa30e0c15f 100644 --- a/libgo/go/crypto/openpgp/packet/public_key.go +++ b/libgo/go/crypto/openpgp/packet/public_key.go @@ -16,11 +16,12 @@ import ( "io" "math/big" "strconv" + "time" ) // PublicKey represents an OpenPGP public key. See RFC 4880, section 5.5.2. type PublicKey struct { - CreationTime uint32 // seconds since the epoch + CreationTime time.Time PubKeyAlgo PublicKeyAlgorithm PublicKey interface{} // Either a *rsa.PublicKey or *dsa.PublicKey Fingerprint [20]byte @@ -38,9 +39,9 @@ func fromBig(n *big.Int) parsedMPI { } // NewRSAPublicKey returns a PublicKey that wraps the given rsa.PublicKey. -func NewRSAPublicKey(creationTimeSecs uint32, pub *rsa.PublicKey, isSubkey bool) *PublicKey { +func NewRSAPublicKey(creationTime time.Time, pub *rsa.PublicKey, isSubkey bool) *PublicKey { pk := &PublicKey{ - CreationTime: creationTimeSecs, + CreationTime: creationTime, PubKeyAlgo: PubKeyAlgoRSA, PublicKey: pub, IsSubkey: isSubkey, @@ -62,7 +63,7 @@ func (pk *PublicKey) parse(r io.Reader) (err error) { if buf[0] != 4 { return error_.UnsupportedError("public key version") } - pk.CreationTime = uint32(buf[1])<<24 | uint32(buf[2])<<16 | uint32(buf[3])<<8 | uint32(buf[4]) + pk.CreationTime = time.Unix(int64(uint32(buf[1])<<24|uint32(buf[2])<<16|uint32(buf[3])<<8|uint32(buf[4])), 0) pk.PubKeyAlgo = PublicKeyAlgorithm(buf[5]) switch pk.PubKeyAlgo { case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: @@ -87,7 +88,7 @@ func (pk *PublicKey) setFingerPrintAndKeyId() { fingerPrint := sha1.New() pk.SerializeSignaturePrefix(fingerPrint) pk.serializeWithoutHeaders(fingerPrint) - copy(pk.Fingerprint[:], fingerPrint.Sum()) + copy(pk.Fingerprint[:], fingerPrint.Sum(nil)) pk.KeyId = binary.BigEndian.Uint64(pk.Fingerprint[12:20]) } @@ -234,10 +235,11 @@ func (pk *PublicKey) Serialize(w io.Writer) (err error) { func (pk *PublicKey) serializeWithoutHeaders(w io.Writer) (err error) { var buf [6]byte buf[0] = 4 - buf[1] = byte(pk.CreationTime >> 24) - buf[2] = byte(pk.CreationTime >> 16) - buf[3] = byte(pk.CreationTime >> 8) - buf[4] = byte(pk.CreationTime) + t := uint32(pk.CreationTime.Unix()) + buf[1] = byte(t >> 24) + buf[2] = byte(t >> 16) + buf[3] = byte(t >> 8) + buf[4] = byte(t) buf[5] = byte(pk.PubKeyAlgo) _, err = w.Write(buf[:]) @@ -269,7 +271,7 @@ func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err erro } signed.Write(sig.HashSuffix) - hashBytes := signed.Sum() + hashBytes := signed.Sum(nil) if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] { return error_.SignatureError("hash tag doesn't match") diff --git a/libgo/go/crypto/openpgp/packet/public_key_test.go b/libgo/go/crypto/openpgp/packet/public_key_test.go index 6e8bfbce66e..72f459f47bf 100644 --- a/libgo/go/crypto/openpgp/packet/public_key_test.go +++ b/libgo/go/crypto/openpgp/packet/public_key_test.go @@ -8,19 +8,20 @@ import ( "bytes" "encoding/hex" "testing" + "time" ) var pubKeyTests = []struct { hexData string hexFingerprint string - creationTime uint32 + creationTime time.Time pubKeyAlgo PublicKeyAlgorithm keyId uint64 keyIdString string keyIdShort string }{ - {rsaPkDataHex, rsaFingerprintHex, 0x4d3c5c10, PubKeyAlgoRSA, 0xa34d7e18c20c31bb, "A34D7E18C20C31BB", "C20C31BB"}, - {dsaPkDataHex, dsaFingerprintHex, 0x4d432f89, PubKeyAlgoDSA, 0x8e8fbe54062f19ed, "8E8FBE54062F19ED", "062F19ED"}, + {rsaPkDataHex, rsaFingerprintHex, time.Unix(0x4d3c5c10, 0), PubKeyAlgoRSA, 0xa34d7e18c20c31bb, "A34D7E18C20C31BB", "C20C31BB"}, + {dsaPkDataHex, dsaFingerprintHex, time.Unix(0x4d432f89, 0), PubKeyAlgoDSA, 0x8e8fbe54062f19ed, "8E8FBE54062F19ED", "062F19ED"}, } func TestPublicKeyRead(t *testing.T) { @@ -38,8 +39,8 @@ func TestPublicKeyRead(t *testing.T) { if pk.PubKeyAlgo != test.pubKeyAlgo { t.Errorf("#%d: bad public key algorithm got:%x want:%x", i, pk.PubKeyAlgo, test.pubKeyAlgo) } - if pk.CreationTime != test.creationTime { - t.Errorf("#%d: bad creation time got:%x want:%x", i, pk.CreationTime, test.creationTime) + if !pk.CreationTime.Equal(test.creationTime) { + t.Errorf("#%d: bad creation time got:%v want:%v", i, pk.CreationTime, test.creationTime) } expectedFingerprint, _ := hex.DecodeString(test.hexFingerprint) if !bytes.Equal(expectedFingerprint, pk.Fingerprint[:]) { diff --git a/libgo/go/crypto/openpgp/packet/signature.go b/libgo/go/crypto/openpgp/packet/signature.go index 4ebb906cad7..1cdc1ee0f0c 100644 --- a/libgo/go/crypto/openpgp/packet/signature.go +++ b/libgo/go/crypto/openpgp/packet/signature.go @@ -15,6 +15,7 @@ import ( "hash" "io" "strconv" + "time" ) // Signature represents a signature. See RFC 4880, section 5.2. @@ -28,7 +29,7 @@ type Signature struct { // HashTag contains the first two bytes of the hash for fast rejection // of bad signed data. HashTag [2]byte - CreationTime uint32 // Unix epoch time + CreationTime time.Time RSASignature parsedMPI DSASigR, DSASigS parsedMPI @@ -151,7 +152,7 @@ func parseSignatureSubpackets(sig *Signature, subpackets []byte, isHashed bool) } } - if sig.CreationTime == 0 { + if sig.CreationTime.IsZero() { err = error_.StructuralError("no creation time in signature") } @@ -223,7 +224,12 @@ func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (r err = error_.StructuralError("signature creation time not four bytes") return } - sig.CreationTime = binary.BigEndian.Uint32(subpacket) + t := binary.BigEndian.Uint32(subpacket) + if t == 0 { + sig.CreationTime = time.Time{} + } else { + sig.CreationTime = time.Unix(int64(t), 0) + } case signatureExpirationSubpacket: // Signature expiration time, section 5.2.3.10 if !isHashed { @@ -417,7 +423,7 @@ func (sig *Signature) signPrepareHash(h hash.Hash) (digest []byte, err error) { } h.Write(sig.HashSuffix) - digest = h.Sum() + digest = h.Sum(nil) copy(sig.HashTag[:], digest) return } @@ -541,10 +547,7 @@ type outputSubpacket struct { func (sig *Signature) buildSubpackets() (subpackets []outputSubpacket) { creationTime := make([]byte, 4) - creationTime[0] = byte(sig.CreationTime >> 24) - creationTime[1] = byte(sig.CreationTime >> 16) - creationTime[2] = byte(sig.CreationTime >> 8) - creationTime[3] = byte(sig.CreationTime) + binary.BigEndian.PutUint32(creationTime, uint32(sig.CreationTime.Unix())) subpackets = append(subpackets, outputSubpacket{true, creationTimeSubpacket, false, creationTime}) if sig.IssuerKeyId != nil { diff --git a/libgo/go/crypto/openpgp/packet/symmetrically_encrypted.go b/libgo/go/crypto/openpgp/packet/symmetrically_encrypted.go index 8225db6d2f6..dff776e3eb2 100644 --- a/libgo/go/crypto/openpgp/packet/symmetrically_encrypted.go +++ b/libgo/go/crypto/openpgp/packet/symmetrically_encrypted.go @@ -201,7 +201,7 @@ func (ser *seMDCReader) Close() error { } ser.h.Write(ser.trailer[:2]) - final := ser.h.Sum() + final := ser.h.Sum(nil) if subtle.ConstantTimeCompare(final, ser.trailer[2:]) != 1 { return error_.SignatureError("hash mismatch") } @@ -227,7 +227,7 @@ func (w *seMDCWriter) Close() (err error) { buf[0] = mdcPacketTagByte buf[1] = sha1.Size w.h.Write(buf[:2]) - digest := w.h.Sum() + digest := w.h.Sum(nil) copy(buf[2:], digest) _, err = w.w.Write(buf[:]) diff --git a/libgo/go/crypto/openpgp/s2k/s2k.go b/libgo/go/crypto/openpgp/s2k/s2k.go index 2a753db16bd..83673e17335 100644 --- a/libgo/go/crypto/openpgp/s2k/s2k.go +++ b/libgo/go/crypto/openpgp/s2k/s2k.go @@ -34,7 +34,7 @@ func Salted(out []byte, h hash.Hash, in []byte, salt []byte) { } h.Write(salt) h.Write(in) - n := copy(out[done:], h.Sum()) + n := copy(out[done:], h.Sum(nil)) done += n } } @@ -68,7 +68,7 @@ func Iterated(out []byte, h hash.Hash, in []byte, salt []byte, count int) { written += len(combined) } } - n := copy(out[done:], h.Sum()) + n := copy(out[done:], h.Sum(nil)) done += n } } diff --git a/libgo/go/crypto/openpgp/write.go b/libgo/go/crypto/openpgp/write.go index 6f3450c9cdb..60dae01e64b 100644 --- a/libgo/go/crypto/openpgp/write.go +++ b/libgo/go/crypto/openpgp/write.go @@ -68,7 +68,7 @@ func detachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.S sig.SigType = sigType sig.PubKeyAlgo = signer.PrivateKey.PubKeyAlgo sig.Hash = crypto.SHA256 - sig.CreationTime = uint32(time.Seconds()) + sig.CreationTime = time.Now() sig.IssuerKeyId = &signer.PrivateKey.KeyId h, wrappedHash, err := hashForSignature(sig.Hash, sig.SigType) @@ -95,8 +95,8 @@ type FileHints struct { // file should not be written to disk. It may be equal to "_CONSOLE" to // suggest the data should not be written to disk. FileName string - // EpochSeconds contains the modification time of the file, or 0 if not applicable. - EpochSeconds uint32 + // ModTime contains the modification time of the file, or the zero time if not applicable. + ModTime time.Time } // SymmetricallyEncrypt acts like gpg -c: it encrypts a file with a passphrase. @@ -115,7 +115,11 @@ func SymmetricallyEncrypt(ciphertext io.Writer, passphrase []byte, hints *FileHi if err != nil { return } - return packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, hints.EpochSeconds) + var epochSeconds uint32 + if !hints.ModTime.IsZero() { + epochSeconds = uint32(hints.ModTime.Unix()) + } + return packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, epochSeconds) } // intersectPreferences mutates and returns a prefix of a that contains only @@ -243,7 +247,11 @@ func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHint w = noOpCloser{encryptedData} } - literalData, err := packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, hints.EpochSeconds) + var epochSeconds uint32 + if !hints.ModTime.IsZero() { + epochSeconds = uint32(hints.ModTime.Unix()) + } + literalData, err := packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, epochSeconds) if err != nil { return nil, err } @@ -275,7 +283,7 @@ func (s signatureWriter) Close() error { SigType: packet.SigTypeBinary, PubKeyAlgo: s.signer.PubKeyAlgo, Hash: s.hashType, - CreationTime: uint32(time.Seconds()), + CreationTime: time.Now(), IssuerKeyId: &s.signer.KeyId, } diff --git a/libgo/go/crypto/openpgp/write_test.go b/libgo/go/crypto/openpgp/write_test.go index 3cadf4cc95a..02fa5b75bff 100644 --- a/libgo/go/crypto/openpgp/write_test.go +++ b/libgo/go/crypto/openpgp/write_test.go @@ -54,7 +54,7 @@ func TestNewEntity(t *testing.T) { return } - e, err := NewEntity(rand.Reader, time.Seconds(), "Test User", "test", "test@example.com") + e, err := NewEntity(rand.Reader, time.Now(), "Test User", "test", "test@example.com") if err != nil { t.Errorf("failed to create entity: %s", err) return diff --git a/libgo/go/crypto/rand/rand_unix.go b/libgo/go/crypto/rand/rand_unix.go index 09442ad2830..d9cddf6d2ad 100644 --- a/libgo/go/crypto/rand/rand_unix.go +++ b/libgo/go/crypto/rand/rand_unix.go @@ -100,7 +100,7 @@ func (r *reader) Read(b []byte) (n int, err error) { // t = encrypt(time) // dst = encrypt(t^seed) // seed = encrypt(t^dst) - ns := time.Nanoseconds() + ns := time.Now().UnixNano() r.time[0] = byte(ns >> 56) r.time[1] = byte(ns >> 48) r.time[2] = byte(ns >> 40) diff --git a/libgo/go/crypto/ripemd160/ripemd160.go b/libgo/go/crypto/ripemd160/ripemd160.go index 6ccfe875f55..c128ee445a5 100644 --- a/libgo/go/crypto/ripemd160/ripemd160.go +++ b/libgo/go/crypto/ripemd160/ripemd160.go @@ -81,7 +81,7 @@ func (d *digest) Write(p []byte) (nn int, err error) { return } -func (d0 *digest) Sum() []byte { +func (d0 *digest) Sum(in []byte) []byte { // Make a copy of d0 so that caller can keep writing and summing. d := new(digest) *d = *d0 @@ -107,11 +107,11 @@ func (d0 *digest) Sum() []byte { panic("d.nx != 0") } - p := make([]byte, 20) - j := 0 for _, s := range d.s { - p[j], p[j+1], p[j+2], p[j+3] = byte(s), byte(s>>8), byte(s>>16), byte(s>>24) - j += 4 + in = append(in, byte(s)) + in = append(in, byte(s>>8)) + in = append(in, byte(s>>16)) + in = append(in, byte(s>>24)) } - return p + return in } diff --git a/libgo/go/crypto/ripemd160/ripemd160_test.go b/libgo/go/crypto/ripemd160/ripemd160_test.go index f4135f5cf65..5df1b2593d2 100644 --- a/libgo/go/crypto/ripemd160/ripemd160_test.go +++ b/libgo/go/crypto/ripemd160/ripemd160_test.go @@ -38,10 +38,10 @@ func TestVectors(t *testing.T) { io.WriteString(md, tv.in) } else { io.WriteString(md, tv.in[0:len(tv.in)/2]) - md.Sum() + md.Sum(nil) io.WriteString(md, tv.in[len(tv.in)/2:]) } - s := fmt.Sprintf("%x", md.Sum()) + s := fmt.Sprintf("%x", md.Sum(nil)) if s != tv.out { t.Fatalf("RIPEMD-160[%d](%s) = %s, expected %s", j, tv.in, s, tv.out) } @@ -56,7 +56,7 @@ func TestMillionA(t *testing.T) { io.WriteString(md, "aaaaaaaaaa") } out := "52783243c1697bdbe16d37f97f68f08325dc1528" - s := fmt.Sprintf("%x", md.Sum()) + s := fmt.Sprintf("%x", md.Sum(nil)) if s != out { t.Fatalf("RIPEMD-160 (1 million 'a') = %s, expected %s", s, out) } diff --git a/libgo/go/crypto/rsa/pkcs1v15_test.go b/libgo/go/crypto/rsa/pkcs1v15_test.go index 66188ac10ed..58d5fda1976 100644 --- a/libgo/go/crypto/rsa/pkcs1v15_test.go +++ b/libgo/go/crypto/rsa/pkcs1v15_test.go @@ -168,7 +168,7 @@ func TestSignPKCS1v15(t *testing.T) { for i, test := range signPKCS1v15Tests { h := sha1.New() h.Write([]byte(test.in)) - digest := h.Sum() + digest := h.Sum(nil) s, err := SignPKCS1v15(nil, rsaPrivateKey, crypto.SHA1, digest) if err != nil { @@ -186,7 +186,7 @@ func TestVerifyPKCS1v15(t *testing.T) { for i, test := range signPKCS1v15Tests { h := sha1.New() h.Write([]byte(test.in)) - digest := h.Sum() + digest := h.Sum(nil) sig, _ := hex.DecodeString(test.out) diff --git a/libgo/go/crypto/rsa/rsa.go b/libgo/go/crypto/rsa/rsa.go index 27ccf61c4fc..f74525c103a 100644 --- a/libgo/go/crypto/rsa/rsa.go +++ b/libgo/go/crypto/rsa/rsa.go @@ -194,7 +194,7 @@ func mgf1XOR(out []byte, hash hash.Hash, seed []byte) { for done < len(out) { hash.Write(seed) hash.Write(counter[0:4]) - digest := hash.Sum() + digest := hash.Sum(nil) hash.Reset() for i := 0; i < len(digest) && done < len(out); i++ { @@ -231,7 +231,7 @@ func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, l } hash.Write(label) - lHash := hash.Sum() + lHash := hash.Sum(nil) hash.Reset() em := make([]byte, k) @@ -428,7 +428,7 @@ func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext } hash.Write(label) - lHash := hash.Sum() + lHash := hash.Sum(nil) hash.Reset() // Converting the plaintext number to bytes will strip any diff --git a/libgo/go/crypto/sha1/sha1.go b/libgo/go/crypto/sha1/sha1.go index 4cdf5b2e989..f41cdb5b027 100644 --- a/libgo/go/crypto/sha1/sha1.go +++ b/libgo/go/crypto/sha1/sha1.go @@ -79,7 +79,7 @@ func (d *digest) Write(p []byte) (nn int, err error) { return } -func (d0 *digest) Sum() []byte { +func (d0 *digest) Sum(in []byte) []byte { // Make a copy of d0 so that caller can keep writing and summing. d := new(digest) *d = *d0 @@ -105,14 +105,11 @@ func (d0 *digest) Sum() []byte { panic("d.nx != 0") } - p := make([]byte, 20) - j := 0 for _, s := range d.h { - p[j+0] = byte(s >> 24) - p[j+1] = byte(s >> 16) - p[j+2] = byte(s >> 8) - p[j+3] = byte(s >> 0) - j += 4 + in = append(in, byte(s>>24)) + in = append(in, byte(s>>16)) + in = append(in, byte(s>>8)) + in = append(in, byte(s)) } - return p + return in } diff --git a/libgo/go/crypto/sha1/sha1_test.go b/libgo/go/crypto/sha1/sha1_test.go index 2712fe35eaf..c23df6c41e9 100644 --- a/libgo/go/crypto/sha1/sha1_test.go +++ b/libgo/go/crypto/sha1/sha1_test.go @@ -60,10 +60,10 @@ func TestGolden(t *testing.T) { io.WriteString(c, g.in) } else { io.WriteString(c, g.in[0:len(g.in)/2]) - c.Sum() + c.Sum(nil) io.WriteString(c, g.in[len(g.in)/2:]) } - s := fmt.Sprintf("%x", c.Sum()) + s := fmt.Sprintf("%x", c.Sum(nil)) if s != g.out { t.Fatalf("sha1[%d](%s) = %s want %s", j, g.in, s, g.out) } diff --git a/libgo/go/crypto/sha256/sha256.go b/libgo/go/crypto/sha256/sha256.go index 14b8cfc7eca..34861f6cf49 100644 --- a/libgo/go/crypto/sha256/sha256.go +++ b/libgo/go/crypto/sha256/sha256.go @@ -123,7 +123,7 @@ func (d *digest) Write(p []byte) (nn int, err error) { return } -func (d0 *digest) Sum() []byte { +func (d0 *digest) Sum(in []byte) []byte { // Make a copy of d0 so that caller can keep writing and summing. d := new(digest) *d = *d0 @@ -149,17 +149,15 @@ func (d0 *digest) Sum() []byte { panic("d.nx != 0") } - p := make([]byte, 32) - j := 0 - for _, s := range d.h { - p[j+0] = byte(s >> 24) - p[j+1] = byte(s >> 16) - p[j+2] = byte(s >> 8) - p[j+3] = byte(s >> 0) - j += 4 - } + h := d.h[:] if d.is224 { - return p[0:28] + h = d.h[:7] } - return p + for _, s := range h { + in = append(in, byte(s>>24)) + in = append(in, byte(s>>16)) + in = append(in, byte(s>>8)) + in = append(in, byte(s)) + } + return in } diff --git a/libgo/go/crypto/sha256/sha256_test.go b/libgo/go/crypto/sha256/sha256_test.go index 42a3fa7a010..a6efb375456 100644 --- a/libgo/go/crypto/sha256/sha256_test.go +++ b/libgo/go/crypto/sha256/sha256_test.go @@ -94,10 +94,10 @@ func TestGolden(t *testing.T) { io.WriteString(c, g.in) } else { io.WriteString(c, g.in[0:len(g.in)/2]) - c.Sum() + c.Sum(nil) io.WriteString(c, g.in[len(g.in)/2:]) } - s := fmt.Sprintf("%x", c.Sum()) + s := fmt.Sprintf("%x", c.Sum(nil)) if s != g.out { t.Fatalf("sha256[%d](%s) = %s want %s", j, g.in, s, g.out) } @@ -112,10 +112,10 @@ func TestGolden(t *testing.T) { io.WriteString(c, g.in) } else { io.WriteString(c, g.in[0:len(g.in)/2]) - c.Sum() + c.Sum(nil) io.WriteString(c, g.in[len(g.in)/2:]) } - s := fmt.Sprintf("%x", c.Sum()) + s := fmt.Sprintf("%x", c.Sum(nil)) if s != g.out { t.Fatalf("sha224[%d](%s) = %s want %s", j, g.in, s, g.out) } diff --git a/libgo/go/crypto/sha512/sha512.go b/libgo/go/crypto/sha512/sha512.go index 1bd27982bb7..3cf65cbe7c8 100644 --- a/libgo/go/crypto/sha512/sha512.go +++ b/libgo/go/crypto/sha512/sha512.go @@ -123,7 +123,7 @@ func (d *digest) Write(p []byte) (nn int, err error) { return } -func (d0 *digest) Sum() []byte { +func (d0 *digest) Sum(in []byte) []byte { // Make a copy of d0 so that caller can keep writing and summing. d := new(digest) *d = *d0 @@ -149,21 +149,19 @@ func (d0 *digest) Sum() []byte { panic("d.nx != 0") } - p := make([]byte, 64) - j := 0 - for _, s := range d.h { - p[j+0] = byte(s >> 56) - p[j+1] = byte(s >> 48) - p[j+2] = byte(s >> 40) - p[j+3] = byte(s >> 32) - p[j+4] = byte(s >> 24) - p[j+5] = byte(s >> 16) - p[j+6] = byte(s >> 8) - p[j+7] = byte(s >> 0) - j += 8 - } + h := d.h[:] if d.is384 { - return p[0:48] + h = d.h[:6] } - return p + for _, s := range h { + in = append(in, byte(s>>56)) + in = append(in, byte(s>>48)) + in = append(in, byte(s>>40)) + in = append(in, byte(s>>32)) + in = append(in, byte(s>>24)) + in = append(in, byte(s>>16)) + in = append(in, byte(s>>8)) + in = append(in, byte(s)) + } + return in } diff --git a/libgo/go/crypto/sha512/sha512_test.go b/libgo/go/crypto/sha512/sha512_test.go index dd116dc17b3..a70f7c54e39 100644 --- a/libgo/go/crypto/sha512/sha512_test.go +++ b/libgo/go/crypto/sha512/sha512_test.go @@ -94,10 +94,10 @@ func TestGolden(t *testing.T) { io.WriteString(c, g.in) } else { io.WriteString(c, g.in[0:len(g.in)/2]) - c.Sum() + c.Sum(nil) io.WriteString(c, g.in[len(g.in)/2:]) } - s := fmt.Sprintf("%x", c.Sum()) + s := fmt.Sprintf("%x", c.Sum(nil)) if s != g.out { t.Fatalf("sha512[%d](%s) = %s want %s", j, g.in, s, g.out) } @@ -112,10 +112,10 @@ func TestGolden(t *testing.T) { io.WriteString(c, g.in) } else { io.WriteString(c, g.in[0:len(g.in)/2]) - c.Sum() + c.Sum(nil) io.WriteString(c, g.in[len(g.in)/2:]) } - s := fmt.Sprintf("%x", c.Sum()) + s := fmt.Sprintf("%x", c.Sum(nil)) if s != g.out { t.Fatalf("sha384[%d](%s) = %s want %s", j, g.in, s, g.out) } diff --git a/libgo/go/crypto/tls/cipher_suites.go b/libgo/go/crypto/tls/cipher_suites.go index 1134f362583..c0e8656f79b 100644 --- a/libgo/go/crypto/tls/cipher_suites.go +++ b/libgo/go/crypto/tls/cipher_suites.go @@ -37,6 +37,7 @@ type keyAgreement interface { // A cipherSuite is a specific combination of key agreement, cipher and MAC // function. All cipher suites currently assume RSA key agreement. type cipherSuite struct { + id uint16 // the lengths, in bytes, of the key material needed for each component. keyLen int macLen int @@ -50,13 +51,13 @@ type cipherSuite struct { mac func(version uint16, macKey []byte) macFunction } -var cipherSuites = map[uint16]*cipherSuite{ - TLS_RSA_WITH_RC4_128_SHA: &cipherSuite{16, 20, 0, rsaKA, false, cipherRC4, macSHA1}, - TLS_RSA_WITH_3DES_EDE_CBC_SHA: &cipherSuite{24, 20, 8, rsaKA, false, cipher3DES, macSHA1}, - TLS_RSA_WITH_AES_128_CBC_SHA: &cipherSuite{16, 20, 16, rsaKA, false, cipherAES, macSHA1}, - TLS_ECDHE_RSA_WITH_RC4_128_SHA: &cipherSuite{16, 20, 0, ecdheRSAKA, true, cipherRC4, macSHA1}, - TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: &cipherSuite{24, 20, 8, ecdheRSAKA, true, cipher3DES, macSHA1}, - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: &cipherSuite{16, 20, 16, ecdheRSAKA, true, cipherAES, macSHA1}, +var cipherSuites = []*cipherSuite{ + &cipherSuite{TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, false, cipherRC4, macSHA1}, + &cipherSuite{TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, rsaKA, false, cipher3DES, macSHA1}, + &cipherSuite{TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, rsaKA, false, cipherAES, macSHA1}, + &cipherSuite{TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, true, cipherRC4, macSHA1}, + &cipherSuite{TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, true, cipher3DES, macSHA1}, + &cipherSuite{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheRSAKA, true, cipherAES, macSHA1}, } func cipherRC4(key, iv []byte, isRead bool) interface{} { @@ -126,13 +127,13 @@ func (s ssl30MAC) MAC(seq, record []byte) []byte { s.h.Write(record[:1]) s.h.Write(record[3:5]) s.h.Write(record[recordHeaderLen:]) - digest := s.h.Sum() + digest := s.h.Sum(nil) s.h.Reset() s.h.Write(s.key) s.h.Write(ssl30Pad2[:padLength]) s.h.Write(digest) - return s.h.Sum() + return s.h.Sum(nil) } // tls10MAC implements the TLS 1.0 MAC function. RFC 2246, section 6.2.3. @@ -148,7 +149,7 @@ func (s tls10MAC) MAC(seq, record []byte) []byte { s.h.Reset() s.h.Write(seq) s.h.Write(record) - return s.h.Sum() + return s.h.Sum(nil) } func rsaKA() keyAgreement { @@ -159,15 +160,20 @@ func ecdheRSAKA() keyAgreement { return new(ecdheRSAKeyAgreement) } -// mutualCipherSuite returns a cipherSuite and its id given a list of supported +// mutualCipherSuite returns a cipherSuite given a list of supported // ciphersuites and the id requested by the peer. -func mutualCipherSuite(have []uint16, want uint16) (suite *cipherSuite, id uint16) { +func mutualCipherSuite(have []uint16, want uint16) *cipherSuite { for _, id := range have { if id == want { - return cipherSuites[id], id + for _, suite := range cipherSuites { + if suite.id == want { + return suite + } + } + return nil } } - return + return nil } // A list of the possible cipher suite ids. Taken from diff --git a/libgo/go/crypto/tls/common.go b/libgo/go/crypto/tls/common.go index ea520859b82..f57d932a98f 100644 --- a/libgo/go/crypto/tls/common.go +++ b/libgo/go/crypto/tls/common.go @@ -121,7 +121,7 @@ type Config struct { // Time returns the current time as the number of seconds since the epoch. // If Time is nil, TLS uses the system time.Seconds. - Time func() int64 + Time func() time.Time // Certificates contains one or more certificate chains // to present to the other side of the connection. @@ -175,10 +175,10 @@ func (c *Config) rand() io.Reader { return r } -func (c *Config) time() int64 { +func (c *Config) time() time.Time { t := c.Time if t == nil { - t = time.Seconds + t = time.Now } return t() } @@ -315,9 +315,7 @@ var ( func initDefaultCipherSuites() { varDefaultCipherSuites = make([]uint16, len(cipherSuites)) - i := 0 - for id := range cipherSuites { - varDefaultCipherSuites[i] = id - i++ + for i, suite := range cipherSuites { + varDefaultCipherSuites[i] = suite.id } } diff --git a/libgo/go/crypto/tls/handshake_client.go b/libgo/go/crypto/tls/handshake_client.go index aed991ccd1b..b4337f2aac6 100644 --- a/libgo/go/crypto/tls/handshake_client.go +++ b/libgo/go/crypto/tls/handshake_client.go @@ -32,7 +32,7 @@ func (c *Conn) clientHandshake() error { nextProtoNeg: len(c.config.NextProtos) > 0, } - t := uint32(c.config.time()) + t := uint32(c.config.time().Unix()) hello.random[0] = byte(t >> 24) hello.random[1] = byte(t >> 16) hello.random[2] = byte(t >> 8) @@ -72,7 +72,7 @@ func (c *Conn) clientHandshake() error { return errors.New("server advertised unrequested NPN") } - suite, suiteId := mutualCipherSuite(c.config.cipherSuites(), serverHello.cipherSuite) + suite := mutualCipherSuite(c.config.cipherSuites(), serverHello.cipherSuite) if suite == nil { return c.sendAlert(alertHandshakeFailure) } @@ -232,8 +232,8 @@ func (c *Conn) clientHandshake() error { if cert != nil { certVerify := new(certificateVerifyMsg) var digest [36]byte - copy(digest[0:16], finishedHash.serverMD5.Sum()) - copy(digest[16:36], finishedHash.serverSHA1.Sum()) + copy(digest[0:16], finishedHash.serverMD5.Sum(nil)) + copy(digest[16:36], finishedHash.serverSHA1.Sum(nil)) signed, err := rsa.SignPKCS1v15(c.config.rand(), c.config.Certificates[0].PrivateKey, crypto.MD5SHA1, digest[0:]) if err != nil { return c.sendAlert(alertInternalError) @@ -292,7 +292,7 @@ func (c *Conn) clientHandshake() error { } c.handshakeComplete = true - c.cipherSuite = suiteId + c.cipherSuite = suite.id return nil } diff --git a/libgo/go/crypto/tls/handshake_server.go b/libgo/go/crypto/tls/handshake_server.go index d5af084eda5..bbb23c0c9f6 100644 --- a/libgo/go/crypto/tls/handshake_server.go +++ b/libgo/go/crypto/tls/handshake_server.go @@ -56,18 +56,25 @@ Curves: ellipticOk := supportedCurve && supportedPointFormat var suite *cipherSuite - var suiteId uint16 FindCipherSuite: for _, id := range clientHello.cipherSuites { for _, supported := range config.cipherSuites() { if id == supported { - suite = cipherSuites[id] + suite = nil + for _, s := range cipherSuites { + if s.id == id { + suite = s + break + } + } + if suite == nil { + continue + } // Don't select a ciphersuite which we can't // support for this client. if suite.elliptic && !ellipticOk { continue } - suiteId = id break FindCipherSuite } } @@ -87,8 +94,8 @@ FindCipherSuite: } hello.vers = vers - hello.cipherSuite = suiteId - t := uint32(config.time()) + hello.cipherSuite = suite.id + t := uint32(config.time().Unix()) hello.random = make([]byte, 32) hello.random[0] = byte(t >> 24) hello.random[1] = byte(t >> 16) @@ -228,8 +235,8 @@ FindCipherSuite: } digest := make([]byte, 36) - copy(digest[0:16], finishedHash.serverMD5.Sum()) - copy(digest[16:36], finishedHash.serverSHA1.Sum()) + copy(digest[0:16], finishedHash.serverMD5.Sum(nil)) + copy(digest[16:36], finishedHash.serverSHA1.Sum(nil)) err = rsa.VerifyPKCS1v15(pub, crypto.MD5SHA1, digest, certVerify.signature) if err != nil { c.sendAlert(alertBadCertificate) @@ -296,7 +303,7 @@ FindCipherSuite: c.writeRecord(recordTypeHandshake, finished.marshal()) c.handshakeComplete = true - c.cipherSuite = suiteId + c.cipherSuite = suite.id return nil } diff --git a/libgo/go/crypto/tls/handshake_server_test.go b/libgo/go/crypto/tls/handshake_server_test.go index bc3797947f5..e00c32c5508 100644 --- a/libgo/go/crypto/tls/handshake_server_test.go +++ b/libgo/go/crypto/tls/handshake_server_test.go @@ -15,6 +15,7 @@ import ( "strconv" "strings" "testing" + "time" ) type zeroSource struct{} @@ -31,7 +32,7 @@ var testConfig *Config func init() { testConfig = new(Config) - testConfig.Time = func() int64 { return 0 } + testConfig.Time = func() time.Time { return time.Unix(0, 0) } testConfig.Rand = zeroSource{} testConfig.Certificates = make([]Certificate, 1) testConfig.Certificates[0].Certificate = [][]byte{testCertificate} diff --git a/libgo/go/crypto/tls/key_agreement.go b/libgo/go/crypto/tls/key_agreement.go index 08fb852d66a..b531717d840 100644 --- a/libgo/go/crypto/tls/key_agreement.go +++ b/libgo/go/crypto/tls/key_agreement.go @@ -90,13 +90,13 @@ func md5SHA1Hash(slices ...[]byte) []byte { for _, slice := range slices { hmd5.Write(slice) } - copy(md5sha1, hmd5.Sum()) + copy(md5sha1, hmd5.Sum(nil)) hsha1 := sha1.New() for _, slice := range slices { hsha1.Write(slice) } - copy(md5sha1[md5.Size:], hsha1.Sum()) + copy(md5sha1[md5.Size:], hsha1.Sum(nil)) return md5sha1 } diff --git a/libgo/go/crypto/tls/prf.go b/libgo/go/crypto/tls/prf.go index d758f21aa8e..637ef03e2d7 100644 --- a/libgo/go/crypto/tls/prf.go +++ b/libgo/go/crypto/tls/prf.go @@ -22,14 +22,14 @@ func splitPreMasterSecret(secret []byte) (s1, s2 []byte) { func pHash(result, secret, seed []byte, hash func() hash.Hash) { h := hmac.New(hash, secret) h.Write(seed) - a := h.Sum() + a := h.Sum(nil) j := 0 for j < len(result) { h.Reset() h.Write(a) h.Write(seed) - b := h.Sum() + b := h.Sum(nil) todo := len(b) if j+todo > len(result) { todo = len(result) - j @@ -39,7 +39,7 @@ func pHash(result, secret, seed []byte, hash func() hash.Hash) { h.Reset() h.Write(a) - a = h.Sum() + a = h.Sum(nil) } } @@ -84,13 +84,13 @@ func pRF30(result, secret, label, seed []byte) { hashSHA1.Write(b[:i+1]) hashSHA1.Write(secret) hashSHA1.Write(seed) - digest := hashSHA1.Sum() + digest := hashSHA1.Sum(nil) hashMD5.Reset() hashMD5.Write(secret) hashMD5.Write(digest) - done += copy(result[done:], hashMD5.Sum()) + done += copy(result[done:], hashMD5.Sum(nil)) i++ } } @@ -182,24 +182,24 @@ func finishedSum30(md5, sha1 hash.Hash, masterSecret []byte, magic [4]byte) []by md5.Write(magic[:]) md5.Write(masterSecret) md5.Write(ssl30Pad1[:]) - md5Digest := md5.Sum() + md5Digest := md5.Sum(nil) md5.Reset() md5.Write(masterSecret) md5.Write(ssl30Pad2[:]) md5.Write(md5Digest) - md5Digest = md5.Sum() + md5Digest = md5.Sum(nil) sha1.Write(magic[:]) sha1.Write(masterSecret) sha1.Write(ssl30Pad1[:40]) - sha1Digest := sha1.Sum() + sha1Digest := sha1.Sum(nil) sha1.Reset() sha1.Write(masterSecret) sha1.Write(ssl30Pad2[:40]) sha1.Write(sha1Digest) - sha1Digest = sha1.Sum() + sha1Digest = sha1.Sum(nil) ret := make([]byte, len(md5Digest)+len(sha1Digest)) copy(ret, md5Digest) @@ -217,8 +217,8 @@ func (h finishedHash) clientSum(masterSecret []byte) []byte { return finishedSum30(h.clientMD5, h.clientSHA1, masterSecret, ssl3ClientFinishedMagic) } - md5 := h.clientMD5.Sum() - sha1 := h.clientSHA1.Sum() + md5 := h.clientMD5.Sum(nil) + sha1 := h.clientSHA1.Sum(nil) return finishedSum10(md5, sha1, clientFinishedLabel, masterSecret) } @@ -229,7 +229,7 @@ func (h finishedHash) serverSum(masterSecret []byte) []byte { return finishedSum30(h.serverMD5, h.serverSHA1, masterSecret, ssl3ServerFinishedMagic) } - md5 := h.serverMD5.Sum() - sha1 := h.serverSHA1.Sum() + md5 := h.serverMD5.Sum(nil) + sha1 := h.serverSHA1.Sum(nil) return finishedSum10(md5, sha1, serverFinishedLabel, masterSecret) } diff --git a/libgo/go/crypto/tls/root_unix.go b/libgo/go/crypto/tls/root_unix.go index 095beec104a..1b9aeb03b5b 100644 --- a/libgo/go/crypto/tls/root_unix.go +++ b/libgo/go/crypto/tls/root_unix.go @@ -14,6 +14,7 @@ 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 } func initDefaultRoots() { diff --git a/libgo/go/crypto/tls/root_windows.go b/libgo/go/crypto/tls/root_windows.go index 13073dcee78..319309ae6e7 100644 --- a/libgo/go/crypto/tls/root_windows.go +++ b/libgo/go/crypto/tls/root_windows.go @@ -6,7 +6,6 @@ package tls import ( "crypto/x509" - "reflect" "syscall" "unsafe" ) @@ -16,29 +15,23 @@ func loadStore(roots *x509.CertPool, name string) { if err != nil { return } + defer syscall.CertCloseStore(store, 0) var cert *syscall.CertContext for { - cert = syscall.CertEnumCertificatesInStore(store, cert) - if cert == nil { - break + cert, err = syscall.CertEnumCertificatesInStore(store, cert) + if err != nil { + return } - var asn1Slice []byte - hdrp := (*reflect.SliceHeader)(unsafe.Pointer(&asn1Slice)) - hdrp.Data = cert.EncodedCert - hdrp.Len = int(cert.Length) - hdrp.Cap = int(cert.Length) - - buf := make([]byte, len(asn1Slice)) - copy(buf, asn1Slice) - - if cert, err := x509.ParseCertificate(buf); err == nil { - roots.AddCert(cert) + buf := (*[1 << 20]byte)(unsafe.Pointer(cert.EncodedCert))[:] + // ParseCertificate requires its own copy of certificate data to keep. + buf2 := make([]byte, cert.Length) + copy(buf2, buf) + if c, err := x509.ParseCertificate(buf2); err == nil { + roots.AddCert(c) } } - - syscall.CertCloseStore(store, 0) } func initDefaultRoots() { diff --git a/libgo/go/crypto/tls/tls.go b/libgo/go/crypto/tls/tls.go index 3ca62407ff0..79ab5023129 100644 --- a/libgo/go/crypto/tls/tls.go +++ b/libgo/go/crypto/tls/tls.go @@ -157,10 +157,21 @@ func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert Certificate, err error) return } - key, err := x509.ParsePKCS1PrivateKey(keyDERBlock.Bytes) - if err != nil { - err = errors.New("crypto/tls: failed to parse key: " + err.Error()) - return + // OpenSSL 0.9.8 generates PKCS#1 private keys by default, while + // OpenSSL 1.0.0 generates PKCS#8 keys. We try both. + var key *rsa.PrivateKey + if key, err = x509.ParsePKCS1PrivateKey(keyDERBlock.Bytes); err != nil { + var privKey interface{} + if privKey, err = x509.ParsePKCS8PrivateKey(keyDERBlock.Bytes); err != nil { + err = errors.New("crypto/tls: failed to parse key: " + err.Error()) + return + } + + var ok bool + if key, ok = privKey.(*rsa.PrivateKey); !ok { + err = errors.New("crypto/tls: found non-RSA private key in PKCS#8 wrapping") + return + } } cert.PrivateKey = key diff --git a/libgo/go/crypto/x509/cert_pool.go b/libgo/go/crypto/x509/cert_pool.go index b9196ed46ed..adc7f9bc6d7 100644 --- a/libgo/go/crypto/x509/cert_pool.go +++ b/libgo/go/crypto/x509/cert_pool.go @@ -8,7 +8,7 @@ import ( "encoding/pem" ) -// Roots is a set of certificates. +// CertPool is a set of certificates. type CertPool struct { bySubjectKeyId map[string][]int byName map[string][]int @@ -70,11 +70,11 @@ func (s *CertPool) AddCert(cert *Certificate) { s.byName[name] = append(s.byName[name], n) } -// AppendCertsFromPEM attempts to parse a series of PEM encoded root -// certificates. It appends any certificates found to s and returns true if any -// certificates were successfully parsed. +// AppendCertsFromPEM attempts to parse a series of PEM encoded certificates. +// It appends any certificates found to s and returns true if any certificates +// were successfully parsed. // -// On many Linux systems, /etc/ssl/cert.pem will contains the system wide set +// On many Linux systems, /etc/ssl/cert.pem will contain the system wide set // of root CAs in a format suitable for this function. func (s *CertPool) AppendCertsFromPEM(pemCerts []byte) (ok bool) { for len(pemCerts) > 0 { diff --git a/libgo/go/crypto/x509/pkcs8.go b/libgo/go/crypto/x509/pkcs8.go new file mode 100644 index 00000000000..4d8e0518e02 --- /dev/null +++ b/libgo/go/crypto/x509/pkcs8.go @@ -0,0 +1,42 @@ +// 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 x509 + +import ( + "crypto/x509/pkix" + "encoding/asn1" + "errors" + "fmt" +) + +// pkcs8 reflects an ASN.1, PKCS#8 PrivateKey. See +// ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-8/pkcs-8v1_2.asn. +type pkcs8 struct { + Version int + Algo pkix.AlgorithmIdentifier + PrivateKey []byte + // optional attributes omitted. +} + +// ParsePKCS8PrivateKey parses an unencrypted, PKCS#8 private key. See +// http://www.rsa.com/rsalabs/node.asp?id=2130 +func ParsePKCS8PrivateKey(der []byte) (key interface{}, err error) { + var privKey pkcs8 + if _, err := asn1.Unmarshal(der, &privKey); err != nil { + return nil, err + } + switch { + case privKey.Algo.Algorithm.Equal(oidRSA): + key, err = ParsePKCS1PrivateKey(privKey.PrivateKey) + if err != nil { + return nil, errors.New("crypto/x509: failed to parse RSA private key embedded in PKCS#8: " + err.Error()) + } + return key, nil + default: + return nil, fmt.Errorf("crypto/x509: PKCS#8 wrapping contained private key with unknown algorithm: %v", privKey.Algo.Algorithm) + } + + panic("unreachable") +} diff --git a/libgo/go/crypto/x509/pkcs8_test.go b/libgo/go/crypto/x509/pkcs8_test.go new file mode 100644 index 00000000000..372005f908c --- /dev/null +++ b/libgo/go/crypto/x509/pkcs8_test.go @@ -0,0 +1,20 @@ +// 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 x509 + +import ( + "encoding/hex" + "testing" +) + +var pkcs8PrivateKeyHex = `30820278020100300d06092a864886f70d0101010500048202623082025e02010002818100cfb1b5bf9685ffa97b4f99df4ff122b70e59ac9b992f3bc2b3dde17d53c1a34928719b02e8fd17839499bfbd515bd6ef99c7a1c47a239718fe36bfd824c0d96060084b5f67f0273443007a24dfaf5634f7772c9346e10eb294c2306671a5a5e719ae24b4de467291bc571014b0e02dec04534d66a9bb171d644b66b091780e8d020301000102818100b595778383c4afdbab95d2bfed12b3f93bb0a73a7ad952f44d7185fd9ec6c34de8f03a48770f2009c8580bcd275e9632714e9a5e3f32f29dc55474b2329ff0ebc08b3ffcb35bc96e6516b483df80a4a59cceb71918cbabf91564e64a39d7e35dce21cb3031824fdbc845dba6458852ec16af5dddf51a8397a8797ae0337b1439024100ea0eb1b914158c70db39031dd8904d6f18f408c85fbbc592d7d20dee7986969efbda081fdf8bc40e1b1336d6b638110c836bfdc3f314560d2e49cd4fbde1e20b024100e32a4e793b574c9c4a94c8803db5152141e72d03de64e54ef2c8ed104988ca780cd11397bc359630d01b97ebd87067c5451ba777cf045ca23f5912f1031308c702406dfcdbbd5a57c9f85abc4edf9e9e29153507b07ce0a7ef6f52e60dcfebe1b8341babd8b789a837485da6c8d55b29bbb142ace3c24a1f5b54b454d01b51e2ad03024100bd6a2b60dee01e1b3bfcef6a2f09ed027c273cdbbaf6ba55a80f6dcc64e4509ee560f84b4f3e076bd03b11e42fe71a3fdd2dffe7e0902c8584f8cad877cdc945024100aa512fa4ada69881f1d8bb8ad6614f192b83200aef5edf4811313d5ef30a86cbd0a90f7b025c71ea06ec6b34db6306c86b1040670fd8654ad7291d066d06d031` + +func TestPKCS8(t *testing.T) { + derBytes, _ := hex.DecodeString(pkcs8PrivateKeyHex) + _, err := ParsePKCS8PrivateKey(derBytes) + if err != nil { + t.Errorf("failed to decode PKCS8 key: %s", err) + } +} diff --git a/libgo/go/crypto/x509/pkix/pkix.go b/libgo/go/crypto/x509/pkix/pkix.go index b35274c9ae1..8eced55f932 100644 --- a/libgo/go/crypto/x509/pkix/pkix.go +++ b/libgo/go/crypto/x509/pkix/pkix.go @@ -142,10 +142,9 @@ type CertificateList struct { SignatureValue asn1.BitString } -// HasExpired returns true iff currentTimeSeconds is past the expiry time of -// certList. -func (certList *CertificateList) HasExpired(currentTimeSeconds int64) bool { - return certList.TBSCertList.NextUpdate.Seconds() <= currentTimeSeconds +// HasExpired returns true iff now is past the expiry time of certList. +func (certList *CertificateList) HasExpired(now time.Time) bool { + return now.After(certList.TBSCertList.NextUpdate) } // TBSCertificateList represents the ASN.1 structure of the same name. See RFC @@ -155,8 +154,8 @@ type TBSCertificateList struct { Version int `asn1:"optional,default:2"` Signature AlgorithmIdentifier Issuer RDNSequence - ThisUpdate *time.Time - NextUpdate *time.Time + ThisUpdate time.Time + NextUpdate time.Time RevokedCertificates []RevokedCertificate `asn1:"optional"` Extensions []Extension `asn1:"tag:0,optional,explicit"` } @@ -165,6 +164,6 @@ type TBSCertificateList struct { // 5280, section 5.1. type RevokedCertificate struct { SerialNumber *big.Int - RevocationTime *time.Time + RevocationTime time.Time Extensions []Extension `asn1:"optional"` } diff --git a/libgo/go/crypto/x509/verify.go b/libgo/go/crypto/x509/verify.go index 3021d20a67f..50a3b66e555 100644 --- a/libgo/go/crypto/x509/verify.go +++ b/libgo/go/crypto/x509/verify.go @@ -76,7 +76,7 @@ type VerifyOptions struct { DNSName string Intermediates *CertPool Roots *CertPool - CurrentTime int64 // if 0, the current system time is used. + CurrentTime time.Time // if zero, the current time is used } const ( @@ -87,8 +87,11 @@ const ( // isValid performs validity checks on the c. func (c *Certificate) isValid(certType int, opts *VerifyOptions) error { - if opts.CurrentTime < c.NotBefore.Seconds() || - opts.CurrentTime > c.NotAfter.Seconds() { + now := opts.CurrentTime + if now.IsZero() { + now = time.Now() + } + if now.Before(c.NotBefore) || now.After(c.NotAfter) { return CertificateInvalidError{c, Expired} } @@ -136,9 +139,6 @@ func (c *Certificate) isValid(certType int, opts *VerifyOptions) error { // // WARNING: this doesn't do any revocation checking. func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) { - if opts.CurrentTime == 0 { - opts.CurrentTime = time.Seconds() - } err = c.isValid(leafCertificate, &opts) if err != nil { return diff --git a/libgo/go/crypto/x509/verify_test.go b/libgo/go/crypto/x509/verify_test.go index 2194d15bc88..df5443023ff 100644 --- a/libgo/go/crypto/x509/verify_test.go +++ b/libgo/go/crypto/x509/verify_test.go @@ -10,6 +10,7 @@ import ( "errors" "strings" "testing" + "time" ) type verifyTest struct { @@ -133,7 +134,7 @@ func TestVerify(t *testing.T) { Roots: NewCertPool(), Intermediates: NewCertPool(), DNSName: test.dnsName, - CurrentTime: test.currentTime, + CurrentTime: time.Unix(test.currentTime, 0), } for j, root := range test.roots { diff --git a/libgo/go/crypto/x509/x509.go b/libgo/go/crypto/x509/x509.go index 9ff7db9a0f9..7e6b5c96f53 100644 --- a/libgo/go/crypto/x509/x509.go +++ b/libgo/go/crypto/x509/x509.go @@ -107,7 +107,7 @@ type dsaSignature struct { } type validity struct { - NotBefore, NotAfter *time.Time + NotBefore, NotAfter time.Time } type publicKeyInfo struct { @@ -303,7 +303,7 @@ type Certificate struct { SerialNumber *big.Int Issuer pkix.Name Subject pkix.Name - NotBefore, NotAfter *time.Time // Validity bounds. + NotBefore, NotAfter time.Time // Validity bounds. KeyUsage KeyUsage ExtKeyUsage []ExtKeyUsage // Sequence of extended key usages. @@ -398,7 +398,7 @@ func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature } h.Write(signed) - digest := h.Sum() + digest := h.Sum(nil) switch pub := c.PublicKey.(type) { case *rsa.PublicKey: @@ -899,11 +899,10 @@ var ( oidRSA = []int{1, 2, 840, 113549, 1, 1, 1} ) -// CreateSelfSignedCertificate creates a new certificate based on -// a template. The following members of template are used: SerialNumber, -// Subject, NotBefore, NotAfter, KeyUsage, BasicConstraintsValid, IsCA, -// MaxPathLen, SubjectKeyId, DNSNames, PermittedDNSDomainsCritical, -// PermittedDNSDomains. +// 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, +// DNSNames, PermittedDNSDomainsCritical, PermittedDNSDomains. // // The certificate is signed by parent. If parent is equal to template then the // certificate is self-signed. The parameter pub is the public key of the @@ -958,7 +957,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.P h := sha1.New() h.Write(tbsCertContents) - digest := h.Sum() + digest := h.Sum(nil) signature, err := rsa.SignPKCS1v15(rand, priv, crypto.SHA1, digest) if err != nil { @@ -1006,7 +1005,7 @@ 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) { +func (c *Certificate) CreateCRL(rand io.Reader, priv *rsa.PrivateKey, revokedCerts []pkix.RevokedCertificate, now, expiry time.Time) (crlBytes []byte, err error) { tbsCertList := pkix.TBSCertificateList{ Version: 2, Signature: pkix.AlgorithmIdentifier{ @@ -1025,7 +1024,7 @@ func (c *Certificate) CreateCRL(rand io.Reader, priv *rsa.PrivateKey, revokedCer h := sha1.New() h.Write(tbsCertListContents) - digest := h.Sum() + digest := h.Sum(nil) signature, err := rsa.SignPKCS1v15(rand, priv, crypto.SHA1, digest) if err != nil { diff --git a/libgo/go/crypto/x509/x509_test.go b/libgo/go/crypto/x509/x509_test.go index c42471507be..f0327b0124d 100644 --- a/libgo/go/crypto/x509/x509_test.go +++ b/libgo/go/crypto/x509/x509_test.go @@ -250,8 +250,8 @@ func TestCreateSelfSignedCertificate(t *testing.T) { CommonName: commonName, Organization: []string{"Acme Co"}, }, - NotBefore: time.SecondsToUTC(1000), - NotAfter: time.SecondsToUTC(100000), + NotBefore: time.Unix(1000, 0), + NotAfter: time.Unix(100000, 0), SubjectKeyId: []byte{1, 2, 3, 4}, KeyUsage: KeyUsageCertSign, @@ -396,8 +396,8 @@ func TestCRLCreation(t *testing.T) { block, _ = pem.Decode([]byte(pemCertificate)) cert, _ := ParseCertificate(block.Bytes) - now := time.SecondsToUTC(1000) - expiry := time.SecondsToUTC(10000) + now := time.Unix(1000, 0) + expiry := time.Unix(10000, 0) revokedCerts := []pkix.RevokedCertificate{ { @@ -443,7 +443,7 @@ func TestParseDERCRL(t *testing.T) { t.Errorf("bad number of revoked certificates. got: %d want: %d", numCerts, expected) } - if certList.HasExpired(1302517272) { + if certList.HasExpired(time.Unix(1302517272, 0)) { t.Errorf("CRL has expired (but shouldn't have)") } @@ -463,7 +463,7 @@ func TestParsePEMCRL(t *testing.T) { t.Errorf("bad number of revoked certificates. got: %d want: %d", numCerts, expected) } - if certList.HasExpired(1302517272) { + if certList.HasExpired(time.Unix(1302517272, 0)) { t.Errorf("CRL has expired (but shouldn't have)") } diff --git a/libgo/go/encoding/asn1/asn1.go b/libgo/go/encoding/asn1/asn1.go index a0066654f8d..22a0dde0da4 100644 --- a/libgo/go/encoding/asn1/asn1.go +++ b/libgo/go/encoding/asn1/asn1.go @@ -247,7 +247,7 @@ func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, err error) // UTCTime -func parseUTCTime(bytes []byte) (ret *time.Time, err error) { +func parseUTCTime(bytes []byte) (ret time.Time, err error) { s := string(bytes) ret, err = time.Parse("0601021504Z0700", s) if err == nil { @@ -259,7 +259,7 @@ func parseUTCTime(bytes []byte) (ret *time.Time, err error) { // parseGeneralizedTime parses the GeneralizedTime from the given byte slice // and returns the resulting time. -func parseGeneralizedTime(bytes []byte) (ret *time.Time, err error) { +func parseGeneralizedTime(bytes []byte) (ret time.Time, err error) { return time.Parse("20060102150405Z0700", string(bytes)) } @@ -450,7 +450,7 @@ var ( objectIdentifierType = reflect.TypeOf(ObjectIdentifier{}) enumeratedType = reflect.TypeOf(Enumerated(0)) flagType = reflect.TypeOf(Flag(false)) - timeType = reflect.TypeOf(&time.Time{}) + timeType = reflect.TypeOf(time.Time{}) rawValueType = reflect.TypeOf(RawValue{}) rawContentsType = reflect.TypeOf(RawContent(nil)) bigIntType = reflect.TypeOf(new(big.Int)) @@ -647,7 +647,7 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam err = err1 return case timeType: - var time *time.Time + var time time.Time var err1 error if universalTag == tagUTCTime { time, err1 = parseUTCTime(innerBytes) @@ -799,7 +799,7 @@ func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) { // // An ASN.1 ENUMERATED can be written to an Enumerated. // -// An ASN.1 UTCTIME or GENERALIZEDTIME can be written to a *time.Time. +// An ASN.1 UTCTIME or GENERALIZEDTIME can be written to a time.Time. // // An ASN.1 PrintableString or IA5String can be written to a string. // diff --git a/libgo/go/encoding/asn1/asn1_test.go b/libgo/go/encoding/asn1/asn1_test.go index 1c529bdb30c..2e6fccf7b80 100644 --- a/libgo/go/encoding/asn1/asn1_test.go +++ b/libgo/go/encoding/asn1/asn1_test.go @@ -202,43 +202,51 @@ func TestObjectIdentifier(t *testing.T) { type timeTest struct { in string ok bool - out *time.Time + out time.Time } var utcTestData = []timeTest{ - {"910506164540-0700", true, &time.Time{1991, 05, 06, 16, 45, 40, 0, -7 * 60 * 60, ""}}, - {"910506164540+0730", true, &time.Time{1991, 05, 06, 16, 45, 40, 0, 7*60*60 + 30*60, ""}}, - {"910506234540Z", true, &time.Time{1991, 05, 06, 23, 45, 40, 0, 0, "UTC"}}, - {"9105062345Z", true, &time.Time{1991, 05, 06, 23, 45, 0, 0, 0, "UTC"}}, - {"a10506234540Z", false, nil}, - {"91a506234540Z", false, nil}, - {"9105a6234540Z", false, nil}, - {"910506a34540Z", false, nil}, - {"910506334a40Z", false, nil}, - {"91050633444aZ", false, nil}, - {"910506334461Z", false, nil}, - {"910506334400Za", false, nil}, + {"910506164540-0700", true, time.Date(1991, 05, 06, 16, 45, 40, 0, time.FixedZone("", -7*60*60))}, + {"910506164540+0730", true, time.Date(1991, 05, 06, 16, 45, 40, 0, time.FixedZone("", 7*60*60+30*60))}, + {"910506234540Z", true, time.Date(1991, 05, 06, 23, 45, 40, 0, time.UTC)}, + {"9105062345Z", true, time.Date(1991, 05, 06, 23, 45, 0, 0, time.UTC)}, + {"a10506234540Z", false, time.Time{}}, + {"91a506234540Z", false, time.Time{}}, + {"9105a6234540Z", false, time.Time{}}, + {"910506a34540Z", false, time.Time{}}, + {"910506334a40Z", false, time.Time{}}, + {"91050633444aZ", false, time.Time{}}, + {"910506334461Z", false, time.Time{}}, + {"910506334400Za", false, time.Time{}}, } func TestUTCTime(t *testing.T) { for i, test := range utcTestData { ret, err := parseUTCTime([]byte(test.in)) - if (err == nil) != test.ok { - t.Errorf("#%d: Incorrect error result (did fail? %v, expected: %v)", i, err == nil, test.ok) - } - if err == nil { - if !reflect.DeepEqual(test.out, ret) { - t.Errorf("#%d: Bad result: %v (expected %v)", i, ret, test.out) + if err != nil { + if test.ok { + t.Errorf("#%d: parseUTCTime(%q) = error %v", i, err) } + continue + } + if !test.ok { + t.Errorf("#%d: parseUTCTime(%q) succeeded, should have failed", i) + continue + } + const format = "Jan _2 15:04:05 -0700 2006" // ignore zone name, just offset + have := ret.Format(format) + want := test.out.Format(format) + if have != want { + t.Errorf("#%d: parseUTCTime(%q) = %s, want %s", test.in, have, want) } } } var generalizedTimeTestData = []timeTest{ - {"20100102030405Z", true, &time.Time{2010, 01, 02, 03, 04, 05, 0, 0, "UTC"}}, - {"20100102030405", false, nil}, - {"20100102030405+0607", true, &time.Time{2010, 01, 02, 03, 04, 05, 0, 6*60*60 + 7*60, ""}}, - {"20100102030405-0607", true, &time.Time{2010, 01, 02, 03, 04, 05, 0, -6*60*60 - 7*60, ""}}, + {"20100102030405Z", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.UTC)}, + {"20100102030405", false, time.Time{}}, + {"20100102030405+0607", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", 6*60*60+7*60))}, + {"20100102030405-0607", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", -6*60*60-7*60))}, } func TestGeneralizedTime(t *testing.T) { @@ -407,7 +415,7 @@ type AttributeTypeAndValue struct { } type Validity struct { - NotBefore, NotAfter *time.Time + NotBefore, NotAfter time.Time } type PublicKeyInfo struct { @@ -475,7 +483,10 @@ var derEncodedSelfSignedCert = Certificate{ RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 3}, Value: "false.example.com"}}, RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}, Value: "false@example.com"}}, }, - Validity: Validity{NotBefore: &time.Time{Year: 2009, Month: 10, Day: 8, Hour: 0, Minute: 25, Second: 53, ZoneOffset: 0, Zone: "UTC"}, NotAfter: &time.Time{Year: 2010, Month: 10, Day: 8, Hour: 0, Minute: 25, Second: 53, ZoneOffset: 0, Zone: "UTC"}}, + Validity: Validity{ + NotBefore: time.Date(2009, 10, 8, 00, 25, 53, 0, time.UTC), + NotAfter: time.Date(2010, 10, 8, 00, 25, 53, 0, time.UTC), + }, Subject: RDNSequence{ RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 6}, Value: "XX"}}, RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 8}, Value: "Some-State"}}, diff --git a/libgo/go/encoding/asn1/marshal.go b/libgo/go/encoding/asn1/marshal.go index 89c50a70ef4..c181e43f979 100644 --- a/libgo/go/encoding/asn1/marshal.go +++ b/libgo/go/encoding/asn1/marshal.go @@ -288,52 +288,58 @@ func marshalTwoDigits(out *forkableWriter, v int) (err error) { return out.WriteByte(byte('0' + v%10)) } -func marshalUTCTime(out *forkableWriter, t *time.Time) (err error) { +func marshalUTCTime(out *forkableWriter, t time.Time) (err error) { + utc := t.UTC() + year, month, day := utc.Date() + switch { - case 1950 <= t.Year && t.Year < 2000: - err = marshalTwoDigits(out, int(t.Year-1900)) - case 2000 <= t.Year && t.Year < 2050: - err = marshalTwoDigits(out, int(t.Year-2000)) + case 1950 <= year && year < 2000: + err = marshalTwoDigits(out, int(year-1900)) + case 2000 <= year && year < 2050: + err = marshalTwoDigits(out, int(year-2000)) default: return StructuralError{"Cannot represent time as UTCTime"} } - if err != nil { return } - err = marshalTwoDigits(out, t.Month) + err = marshalTwoDigits(out, int(month)) if err != nil { return } - err = marshalTwoDigits(out, t.Day) + err = marshalTwoDigits(out, day) if err != nil { return } - err = marshalTwoDigits(out, t.Hour) + hour, min, sec := utc.Clock() + + err = marshalTwoDigits(out, hour) if err != nil { return } - err = marshalTwoDigits(out, t.Minute) + err = marshalTwoDigits(out, min) if err != nil { return } - err = marshalTwoDigits(out, t.Second) + err = marshalTwoDigits(out, sec) if err != nil { return } + _, offset := t.Zone() + switch { - case t.ZoneOffset/60 == 0: + case offset/60 == 0: err = out.WriteByte('Z') return - case t.ZoneOffset > 0: + case offset > 0: err = out.WriteByte('+') - case t.ZoneOffset < 0: + case offset < 0: err = out.WriteByte('-') } @@ -341,7 +347,7 @@ func marshalUTCTime(out *forkableWriter, t *time.Time) (err error) { return } - offsetMinutes := t.ZoneOffset / 60 + offsetMinutes := offset / 60 if offsetMinutes < 0 { offsetMinutes = -offsetMinutes } @@ -366,7 +372,7 @@ func stripTagAndLength(in []byte) []byte { func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameters) (err error) { switch value.Type() { case timeType: - return marshalUTCTime(out, value.Interface().(*time.Time)) + return marshalUTCTime(out, value.Interface().(time.Time)) case bitStringType: return marshalBitString(out, value.Interface().(BitString)) case objectIdentifierType: diff --git a/libgo/go/encoding/asn1/marshal_test.go b/libgo/go/encoding/asn1/marshal_test.go index 03df5f1e1d5..d05b5d8d4e9 100644 --- a/libgo/go/encoding/asn1/marshal_test.go +++ b/libgo/go/encoding/asn1/marshal_test.go @@ -51,10 +51,7 @@ type optionalRawValueTest struct { type testSET []int -func setPST(t *time.Time) *time.Time { - t.ZoneOffset = -28800 - return t -} +var PST = time.FixedZone("PST", -8*60*60) type marshalTest struct { in interface{} @@ -73,9 +70,9 @@ var marshalTests = []marshalTest{ {[]byte{1, 2, 3}, "0403010203"}, {implicitTagTest{64}, "3003850140"}, {explicitTagTest{64}, "3005a503020140"}, - {time.SecondsToUTC(0), "170d3730303130313030303030305a"}, - {time.SecondsToUTC(1258325776), "170d3039313131353232353631365a"}, - {setPST(time.SecondsToUTC(1258325776)), "17113039313131353232353631362d30383030"}, + {time.Unix(0, 0).UTC(), "170d3730303130313030303030305a"}, + {time.Unix(1258325776, 0).UTC(), "170d3039313131353232353631365a"}, + {time.Unix(1258325776, 0).In(PST), "17113039313131353232353631362d30383030"}, {BitString{[]byte{0x80}, 1}, "03020780"}, {BitString{[]byte{0x81, 0xf0}, 12}, "03030481f0"}, {ObjectIdentifier([]int{1, 2, 3, 4}), "06032a0304"}, @@ -123,7 +120,8 @@ func TestMarshal(t *testing.T) { } out, _ := hex.DecodeString(test.out) if bytes.Compare(out, data) != 0 { - t.Errorf("#%d got: %x want %x", i, data, out) + t.Errorf("#%d got: %x want %x\n\t%q\n\t%q", i, data, out, data, out) + } } } diff --git a/libgo/go/encoding/json/encode.go b/libgo/go/encoding/json/encode.go index 35964c5d9c2..14284f50e47 100644 --- a/libgo/go/encoding/json/encode.go +++ b/libgo/go/encoding/json/encode.go @@ -16,6 +16,7 @@ import ( "runtime" "sort" "strconv" + "sync" "unicode" "unicode/utf8" ) @@ -295,28 +296,10 @@ func (e *encodeState) reflectValueQuoted(v reflect.Value, quoted bool) { case reflect.Struct: e.WriteByte('{') - t := v.Type() - n := v.NumField() first := true - for i := 0; i < n; i++ { - f := t.Field(i) - if f.PkgPath != "" { - continue - } - tag, omitEmpty, quoted := f.Name, false, false - if tv := f.Tag.Get("json"); tv != "" { - if tv == "-" { - continue - } - name, opts := parseTag(tv) - if isValidTag(name) { - tag = name - } - omitEmpty = opts.Contains("omitempty") - quoted = opts.Contains("string") - } - fieldValue := v.Field(i) - if omitEmpty && isEmptyValue(fieldValue) { + for _, ef := range encodeFields(v.Type()) { + fieldValue := v.Field(ef.i) + if ef.omitEmpty && isEmptyValue(fieldValue) { continue } if first { @@ -324,9 +307,9 @@ func (e *encodeState) reflectValueQuoted(v reflect.Value, quoted bool) { } else { e.WriteByte(',') } - e.string(tag) + e.string(ef.tag) e.WriteByte(':') - e.reflectValueQuoted(fieldValue, quoted) + e.reflectValueQuoted(fieldValue, ef.quoted) } e.WriteByte('}') @@ -470,3 +453,63 @@ func (e *encodeState) string(s string) (int, error) { e.WriteByte('"') return e.Len() - len0, nil } + +// encodeField contains information about how to encode a field of a +// struct. +type encodeField struct { + i int // field index in struct + tag string + quoted bool + omitEmpty bool +} + +var ( + typeCacheLock sync.RWMutex + encodeFieldsCache = make(map[reflect.Type][]encodeField) +) + +// encodeFields returns a slice of encodeField for a given +// struct type. +func encodeFields(t reflect.Type) []encodeField { + typeCacheLock.RLock() + fs, ok := encodeFieldsCache[t] + typeCacheLock.RUnlock() + if ok { + return fs + } + + typeCacheLock.Lock() + defer typeCacheLock.Unlock() + fs, ok = encodeFieldsCache[t] + if ok { + return fs + } + + v := reflect.Zero(t) + n := v.NumField() + for i := 0; i < n; i++ { + f := t.Field(i) + if f.PkgPath != "" { + continue + } + var ef encodeField + ef.i = i + ef.tag = f.Name + + tv := f.Tag.Get("json") + if tv != "" { + if tv == "-" { + continue + } + name, opts := parseTag(tv) + if isValidTag(name) { + ef.tag = name + } + ef.omitEmpty = opts.Contains("omitempty") + ef.quoted = opts.Contains("string") + } + fs = append(fs, ef) + } + encodeFieldsCache[t] = fs + return fs +} diff --git a/libgo/go/encoding/xml/xml.go b/libgo/go/encoding/xml/xml.go index 216d8889b23..d67a299f5bb 100644 --- a/libgo/go/encoding/xml/xml.go +++ b/libgo/go/encoding/xml/xml.go @@ -61,7 +61,7 @@ type StartElement struct { func (e StartElement) Copy() StartElement { attrs := make([]Attr, len(e.Attr)) - copy(e.Attr, attrs) + copy(attrs, e.Attr) e.Attr = attrs return e } diff --git a/libgo/go/encoding/xml/xml_test.go b/libgo/go/encoding/xml/xml_test.go index bcb22afde00..25ffc917dcb 100644 --- a/libgo/go/encoding/xml/xml_test.go +++ b/libgo/go/encoding/xml/xml_test.go @@ -29,71 +29,69 @@ const testInput = ` ` var rawTokens = []Token{ - CharData([]byte("\n")), + CharData("\n"), ProcInst{"xml", []byte(`version="1.0" encoding="UTF-8"`)}, - CharData([]byte("\n")), - Directive([]byte(`DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + CharData("\n"), + Directive(`DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"`), - ), - CharData([]byte("\n")), + CharData("\n"), StartElement{Name{"", "body"}, []Attr{{Name{"xmlns", "foo"}, "ns1"}, {Name{"", "xmlns"}, "ns2"}, {Name{"xmlns", "tag"}, "ns3"}}}, - CharData([]byte("\n ")), + CharData("\n "), StartElement{Name{"", "hello"}, []Attr{{Name{"", "lang"}, "en"}}}, - CharData([]byte("World <>'\" 白鵬翔")), + CharData("World <>'\" 白鵬翔"), EndElement{Name{"", "hello"}}, - CharData([]byte("\n ")), + CharData("\n "), StartElement{Name{"", "goodbye"}, []Attr{}}, EndElement{Name{"", "goodbye"}}, - CharData([]byte("\n ")), + CharData("\n "), StartElement{Name{"", "outer"}, []Attr{{Name{"foo", "attr"}, "value"}, {Name{"xmlns", "tag"}, "ns4"}}}, - CharData([]byte("\n ")), + CharData("\n "), StartElement{Name{"", "inner"}, []Attr{}}, EndElement{Name{"", "inner"}}, - CharData([]byte("\n ")), + CharData("\n "), EndElement{Name{"", "outer"}}, - CharData([]byte("\n ")), + CharData("\n "), StartElement{Name{"tag", "name"}, []Attr{}}, - CharData([]byte("\n ")), - CharData([]byte("Some text here.")), - CharData([]byte("\n ")), + CharData("\n "), + CharData("Some text here."), + CharData("\n "), EndElement{Name{"tag", "name"}}, - CharData([]byte("\n")), + CharData("\n"), EndElement{Name{"", "body"}}, - Comment([]byte(" missing final newline ")), + Comment(" missing final newline "), } var cookedTokens = []Token{ - CharData([]byte("\n")), + CharData("\n"), ProcInst{"xml", []byte(`version="1.0" encoding="UTF-8"`)}, - CharData([]byte("\n")), - Directive([]byte(`DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + CharData("\n"), + Directive(`DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"`), - ), - CharData([]byte("\n")), + CharData("\n"), StartElement{Name{"ns2", "body"}, []Attr{{Name{"xmlns", "foo"}, "ns1"}, {Name{"", "xmlns"}, "ns2"}, {Name{"xmlns", "tag"}, "ns3"}}}, - CharData([]byte("\n ")), + CharData("\n "), StartElement{Name{"ns2", "hello"}, []Attr{{Name{"", "lang"}, "en"}}}, - CharData([]byte("World <>'\" 白鵬翔")), + CharData("World <>'\" 白鵬翔"), EndElement{Name{"ns2", "hello"}}, - CharData([]byte("\n ")), + CharData("\n "), StartElement{Name{"ns2", "goodbye"}, []Attr{}}, EndElement{Name{"ns2", "goodbye"}}, - CharData([]byte("\n ")), + CharData("\n "), StartElement{Name{"ns2", "outer"}, []Attr{{Name{"ns1", "attr"}, "value"}, {Name{"xmlns", "tag"}, "ns4"}}}, - CharData([]byte("\n ")), + CharData("\n "), StartElement{Name{"ns2", "inner"}, []Attr{}}, EndElement{Name{"ns2", "inner"}}, - CharData([]byte("\n ")), + CharData("\n "), EndElement{Name{"ns2", "outer"}}, - CharData([]byte("\n ")), + CharData("\n "), StartElement{Name{"ns3", "name"}, []Attr{}}, - CharData([]byte("\n ")), - CharData([]byte("Some text here.")), - CharData([]byte("\n ")), + CharData("\n "), + CharData("Some text here."), + CharData("\n "), EndElement{Name{"ns3", "name"}}, - CharData([]byte("\n")), + CharData("\n"), EndElement{Name{"ns2", "body"}}, - Comment([]byte(" missing final newline ")), + Comment(" missing final newline "), } const testInputAltEncoding = ` @@ -101,11 +99,11 @@ const testInputAltEncoding = ` VALUE` var rawTokensAltEncoding = []Token{ - CharData([]byte("\n")), + CharData("\n"), ProcInst{"xml", []byte(`version="1.0" encoding="x-testing-uppercase"`)}, - CharData([]byte("\n")), + CharData("\n"), StartElement{Name{"", "tag"}, []Attr{}}, - CharData([]byte("value")), + CharData("value"), EndElement{Name{"", "tag"}}, } @@ -270,21 +268,21 @@ var nestedDirectivesInput = ` ` var nestedDirectivesTokens = []Token{ - CharData([]byte("\n")), - Directive([]byte(`DOCTYPE []`)), - CharData([]byte("\n")), - Directive([]byte(`DOCTYPE [">]`)), - CharData([]byte("\n")), - Directive([]byte(`DOCTYPE []`)), - CharData([]byte("\n")), - Directive([]byte(`DOCTYPE ['>]`)), - CharData([]byte("\n")), - Directive([]byte(`DOCTYPE []`)), - CharData([]byte("\n")), - Directive([]byte(`DOCTYPE ['>]`)), - CharData([]byte("\n")), - Directive([]byte(`DOCTYPE []`)), - CharData([]byte("\n")), + CharData("\n"), + Directive(`DOCTYPE []`), + CharData("\n"), + Directive(`DOCTYPE [">]`), + CharData("\n"), + Directive(`DOCTYPE []`), + CharData("\n"), + Directive(`DOCTYPE ['>]`), + CharData("\n"), + Directive(`DOCTYPE []`), + CharData("\n"), + Directive(`DOCTYPE ['>]`), + CharData("\n"), + Directive(`DOCTYPE []`), + CharData("\n"), } func TestNestedDirectives(t *testing.T) { @@ -488,10 +486,13 @@ func TestCopyTokenStartElement(t *testing.T) { elt := StartElement{Name{"", "hello"}, []Attr{{Name{"", "lang"}, "en"}}} var tok1 Token = elt tok2 := CopyToken(tok1) + if tok1.(StartElement).Attr[0].Value != "en" { + t.Error("CopyToken overwrote Attr[0]") + } if !reflect.DeepEqual(tok1, tok2) { t.Error("CopyToken(StartElement) != StartElement") } - elt.Attr[0] = Attr{Name{"", "lang"}, "de"} + tok1.(StartElement).Attr[0] = Attr{Name{"", "lang"}, "de"} if reflect.DeepEqual(tok1, tok2) { t.Error("CopyToken(CharData) uses same buffer.") } diff --git a/libgo/go/exp/gotype/gotype.go b/libgo/go/exp/gotype/gotype.go index bc4a112c98f..a2a9361866d 100644 --- a/libgo/go/exp/gotype/gotype.go +++ b/libgo/go/exp/gotype/gotype.go @@ -150,15 +150,15 @@ func processFiles(filenames []string, allFiles bool) { switch info, err := os.Stat(filename); { case err != nil: report(err) - case info.IsRegular(): - if allFiles || isGoFilename(info.Name) { - filenames[i] = filename - i++ - } - case info.IsDirectory(): + case info.IsDir(): if allFiles || *recursive { processDirectory(filename) } + default: + if allFiles || isGoFilename(info.Name()) { + filenames[i] = filename + i++ + } } } fset := token.NewFileSet() diff --git a/libgo/go/exp/gui/gui.go b/libgo/go/exp/gui/gui.go deleted file mode 100644 index a69f83a1f50..00000000000 --- a/libgo/go/exp/gui/gui.go +++ /dev/null @@ -1,57 +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 gui defines a basic graphical user interface programming model. -package gui - -import ( - "image" - "image/draw" -) - -// A Window represents a single graphics window. -type Window interface { - // Screen returns an editable Image for the window. - Screen() draw.Image - // FlushImage flushes changes made to Screen() back to screen. - FlushImage() - // EventChan returns a channel carrying UI events such as key presses, - // mouse movements and window resizes. - EventChan() <-chan interface{} - // Close closes the window. - Close() error -} - -// A KeyEvent is sent for a key press or release. -type KeyEvent struct { - // The value k represents key k being pressed. - // The value -k represents key k being released. - // The specific set of key values is not specified, - // but ordinary characters represent themselves. - Key int -} - -// A MouseEvent is sent for a button press or release or for a mouse movement. -type MouseEvent struct { - // Buttons is a bit mask of buttons: 1<<0 is left, 1<<1 middle, 1<<2 right. - // It represents button state and not necessarily the state delta: bit 0 - // being on means that the left mouse button is down, but does not imply - // that the same button was up in the previous MouseEvent. - Buttons int - // Loc is the location of the cursor. - Loc image.Point - // Nsec is the event's timestamp. - Nsec int64 -} - -// A ConfigEvent is sent each time the window's color model or size changes. -// The client should respond by calling Window.Screen to obtain a new image. -type ConfigEvent struct { - Config image.Config -} - -// An ErrEvent is sent when an error occurs. -type ErrEvent struct { - Err error -} diff --git a/libgo/go/exp/gui/x11/auth.go b/libgo/go/exp/gui/x11/auth.go deleted file mode 100644 index 24e941cb36b..00000000000 --- a/libgo/go/exp/gui/x11/auth.go +++ /dev/null @@ -1,96 +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 x11 - -import ( - "bufio" - "errors" - "io" - "os" -) - -// readU16BE reads a big-endian uint16 from r, using b as a scratch buffer. -func readU16BE(r io.Reader, b []byte) (uint16, error) { - _, err := io.ReadFull(r, b[0:2]) - if err != nil { - return 0, err - } - return uint16(b[0])<<8 + uint16(b[1]), nil -} - -// readStr reads a length-prefixed string from r, using b as a scratch buffer. -func readStr(r io.Reader, b []byte) (string, error) { - n, err := readU16BE(r, b) - if err != nil { - return "", err - } - if int(n) > len(b) { - return "", errors.New("Xauthority entry too long for buffer") - } - _, err = io.ReadFull(r, b[0:n]) - if err != nil { - return "", err - } - return string(b[0:n]), nil -} - -// readAuth reads the X authority file and returns the name/data pair for the display. -// displayStr is the "12" out of a $DISPLAY like ":12.0". -func readAuth(displayStr string) (name, data string, err error) { - // b is a scratch buffer to use and should be at least 256 bytes long - // (i.e. it should be able to hold a hostname). - var b [256]byte - // As per /usr/include/X11/Xauth.h. - const familyLocal = 256 - - fn := os.Getenv("XAUTHORITY") - if fn == "" { - home := os.Getenv("HOME") - if home == "" { - err = errors.New("Xauthority not found: $XAUTHORITY, $HOME not set") - return - } - fn = home + "/.Xauthority" - } - r, err := os.Open(fn) - if err != nil { - return - } - defer r.Close() - br := bufio.NewReader(r) - - hostname, err := os.Hostname() - if err != nil { - return - } - for { - var family uint16 - var addr, disp, name0, data0 string - family, err = readU16BE(br, b[0:2]) - if err != nil { - return - } - addr, err = readStr(br, b[0:]) - if err != nil { - return - } - disp, err = readStr(br, b[0:]) - if err != nil { - return - } - name0, err = readStr(br, b[0:]) - if err != nil { - return - } - data0, err = readStr(br, b[0:]) - if err != nil { - return - } - if family == familyLocal && addr == hostname && disp == displayStr { - return name0, data0, nil - } - } - panic("unreachable") -} diff --git a/libgo/go/exp/gui/x11/conn.go b/libgo/go/exp/gui/x11/conn.go deleted file mode 100644 index 15afc657ecb..00000000000 --- a/libgo/go/exp/gui/x11/conn.go +++ /dev/null @@ -1,631 +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 x11 implements an X11 backend for the exp/gui package. -// -// The X protocol specification is at ftp://ftp.x.org/pub/X11R7.0/doc/PDF/proto.pdf. -// A summary of the wire format can be found in XCB's xproto.xml. -package x11 - -import ( - "bufio" - "errors" - "exp/gui" - "image" - "image/draw" - "io" - "log" - "net" - "os" - "strconv" - "strings" - "time" -) - -type resID uint32 // X resource IDs. - -// TODO(nigeltao): Handle window resizes. -const ( - windowHeight = 600 - windowWidth = 800 -) - -const ( - keymapLo = 8 - keymapHi = 255 -) - -type conn struct { - c io.Closer - r *bufio.Reader - w *bufio.Writer - - gc, window, root, visual resID - - img *image.RGBA - eventc chan interface{} - mouseState gui.MouseEvent - - buf [256]byte // General purpose scratch buffer. - - flush chan bool - flushBuf0 [24]byte - flushBuf1 [4 * 1024]byte -} - -// writeSocket runs in its own goroutine, serving both FlushImage calls -// directly from the exp/gui client and indirectly from X expose events. -// It paints c.img to the X server via PutImage requests. -func (c *conn) writeSocket() { - defer c.c.Close() - for _ = range c.flush { - b := c.img.Bounds() - if b.Empty() { - continue - } - // Each X request has a 16-bit length (in terms of 4-byte units). To avoid going over - // this limit, we send PutImage for each row of the image, rather than trying to paint - // the entire image in one X request. This approach could easily be optimized (or the - // X protocol may have an escape sequence to delimit very large requests). - // TODO(nigeltao): See what XCB's xcb_put_image does in this situation. - units := 6 + b.Dx() - if units > 0xffff || b.Dy() > 0xffff { - log.Print("x11: window is too large for PutImage") - return - } - - c.flushBuf0[0] = 0x48 // PutImage opcode. - c.flushBuf0[1] = 0x02 // XCB_IMAGE_FORMAT_Z_PIXMAP. - c.flushBuf0[2] = uint8(units) - c.flushBuf0[3] = uint8(units >> 8) - setU32LE(c.flushBuf0[4:8], uint32(c.window)) - setU32LE(c.flushBuf0[8:12], uint32(c.gc)) - setU32LE(c.flushBuf0[12:16], 1<<16|uint32(b.Dx())) - c.flushBuf0[21] = 0x18 // depth = 24 bits. - - for y := b.Min.Y; y < b.Max.Y; y++ { - setU32LE(c.flushBuf0[16:20], uint32(y<<16)) - if _, err := c.w.Write(c.flushBuf0[:24]); err != nil { - if err != io.EOF { - log.Println("x11:", err) - } - return - } - p := c.img.Pix[(y-b.Min.Y)*c.img.Stride:] - for x, dx := 0, 4*b.Dx(); x < dx; { - nx := dx - x - if nx > len(c.flushBuf1) { - nx = len(c.flushBuf1) &^ 3 - } - for i := 0; i < nx; i += 4 { - // X11's order is BGRX, not RGBA. - c.flushBuf1[i+0] = p[x+i+2] - c.flushBuf1[i+1] = p[x+i+1] - c.flushBuf1[i+2] = p[x+i+0] - } - x += nx - if _, err := c.w.Write(c.flushBuf1[:nx]); err != nil { - if err != io.EOF { - log.Println("x11:", err) - } - return - } - } - } - if err := c.w.Flush(); err != nil { - if err != io.EOF { - log.Println("x11:", err) - } - return - } - } -} - -func (c *conn) Screen() draw.Image { return c.img } - -func (c *conn) FlushImage() { - select { - case c.flush <- false: - // Flush notification sent. - default: - // Could not send. - // Flush notification must be pending already. - } -} - -func (c *conn) Close() error { - // Shut down the writeSocket goroutine. This will close the socket to the - // X11 server, which will cause c.eventc to close. - close(c.flush) - for _ = range c.eventc { - // Drain the channel to allow the readSocket goroutine to shut down. - } - return nil -} - -func (c *conn) EventChan() <-chan interface{} { return c.eventc } - -// readSocket runs in its own goroutine, reading X events and sending gui -// events on c's EventChan. -func (c *conn) readSocket() { - var ( - keymap [256][]int - keysymsPerKeycode int - ) - defer close(c.eventc) - for { - // X events are always 32 bytes long. - if _, err := io.ReadFull(c.r, c.buf[:32]); err != nil { - if err != io.EOF { - c.eventc <- gui.ErrEvent{err} - } - return - } - switch c.buf[0] { - case 0x01: // Reply from a request (e.g. GetKeyboardMapping). - cookie := int(c.buf[3])<<8 | int(c.buf[2]) - if cookie != 1 { - // We issued only one request (GetKeyboardMapping) with a cookie of 1, - // so we shouldn't get any other reply from the X server. - c.eventc <- gui.ErrEvent{errors.New("x11: unexpected cookie")} - return - } - keysymsPerKeycode = int(c.buf[1]) - b := make([]int, 256*keysymsPerKeycode) - for i := range keymap { - keymap[i] = b[i*keysymsPerKeycode : (i+1)*keysymsPerKeycode] - } - for i := keymapLo; i <= keymapHi; i++ { - m := keymap[i] - for j := range m { - u, err := readU32LE(c.r, c.buf[:4]) - if err != nil { - if err != io.EOF { - c.eventc <- gui.ErrEvent{err} - } - return - } - m[j] = int(u) - } - } - case 0x02, 0x03: // Key press, key release. - // X Keyboard Encoding is documented at http://tronche.com/gui/x/xlib/input/keyboard-encoding.html - // TODO(nigeltao): Do we need to implement the "MODE SWITCH / group modifier" feature - // or is that some no-longer-used X construct? - if keysymsPerKeycode < 2 { - // Either we haven't yet received the GetKeyboardMapping reply or - // the X server has sent one that's too short. - continue - } - keycode := int(c.buf[1]) - shift := int(c.buf[28]) & 0x01 - keysym := keymap[keycode][shift] - if keysym == 0 { - keysym = keymap[keycode][0] - } - // TODO(nigeltao): Should we send KeyEvents for Shift/Ctrl/Alt? Should Shift-A send - // the same int down the channel as the sent on just the A key? - // TODO(nigeltao): How should IME events (e.g. key presses that should generate CJK text) work? Or - // is that outside the scope of the gui.Window interface? - if c.buf[0] == 0x03 { - keysym = -keysym - } - c.eventc <- gui.KeyEvent{keysym} - case 0x04, 0x05: // Button press, button release. - mask := 1 << (c.buf[1] - 1) - if c.buf[0] == 0x04 { - c.mouseState.Buttons |= mask - } else { - c.mouseState.Buttons &^= mask - } - c.mouseState.Nsec = time.Nanoseconds() - c.eventc <- c.mouseState - case 0x06: // Motion notify. - c.mouseState.Loc.X = int(int16(c.buf[25])<<8 | int16(c.buf[24])) - c.mouseState.Loc.Y = int(int16(c.buf[27])<<8 | int16(c.buf[26])) - c.mouseState.Nsec = time.Nanoseconds() - c.eventc <- c.mouseState - case 0x0c: // Expose. - // A single user action could trigger multiple expose events (e.g. if moving another - // window with XShape'd rounded corners over our window). In that case, the X server will - // send a uint16 count (in bytes 16-17) of the number of additional expose events coming. - // We could parse each event for the (x, y, width, height) and maintain a minimal dirty - // rectangle, but for now, the simplest approach is to paint the entire window, when - // receiving the final event in the series. - if c.buf[17] == 0 && c.buf[16] == 0 { - // TODO(nigeltao): Should we ignore the very first expose event? A freshly mapped window - // will trigger expose, but until the first c.FlushImage call, there's probably nothing to - // paint but black. For an 800x600 window, at 4 bytes per pixel, each repaint writes about - // 2MB over the socket. - c.FlushImage() - } - // TODO(nigeltao): Should we listen to DestroyNotify (0x11) and ResizeRequest (0x19) events? - // What about EnterNotify (0x07) and LeaveNotify (0x08)? - } - } -} - -// connect connects to the X server given by the full X11 display name (e.g. -// ":12.0") and returns the connection as well as the portion of the full name -// that is the display number (e.g. "12"). -// Examples: -// connect(":1") // calls net.Dial("unix", "", "/tmp/.X11-unix/X1"), displayStr="1" -// connect("/tmp/launch-123/:0") // calls net.Dial("unix", "", "/tmp/launch-123/:0"), displayStr="0" -// connect("hostname:2.1") // calls net.Dial("tcp", "", "hostname:6002"), displayStr="2" -// connect("tcp/hostname:1.0") // calls net.Dial("tcp", "", "hostname:6001"), displayStr="1" -func connect(display string) (conn net.Conn, displayStr string, err error) { - colonIdx := strings.LastIndex(display, ":") - if colonIdx < 0 { - return nil, "", errors.New("bad display: " + display) - } - // Parse the section before the colon. - var protocol, host, socket string - if display[0] == '/' { - socket = display[:colonIdx] - } else { - if i := strings.LastIndex(display, "/"); i < 0 { - // The default protocol is TCP. - protocol = "tcp" - host = display[:colonIdx] - } else { - protocol = display[:i] - host = display[i+1 : colonIdx] - } - } - // Parse the section after the colon. - after := display[colonIdx+1:] - if after == "" { - return nil, "", errors.New("bad display: " + display) - } - if i := strings.LastIndex(after, "."); i < 0 { - displayStr = after - } else { - displayStr = after[:i] - } - displayInt, err := strconv.Atoi(displayStr) - if err != nil || displayInt < 0 { - return nil, "", errors.New("bad display: " + display) - } - // Make the connection. - if socket != "" { - conn, err = net.Dial("unix", socket+":"+displayStr) - } else if host != "" { - conn, err = net.Dial(protocol, host+":"+strconv.Itoa(6000+displayInt)) - } else { - conn, err = net.Dial("unix", "/tmp/.X11-unix/X"+displayStr) - } - if err != nil { - return nil, "", errors.New("cannot connect to " + display + ": " + err.Error()) - } - return -} - -// authenticate authenticates ourselves with the X server. -// displayStr is the "12" out of ":12.0". -func authenticate(w *bufio.Writer, displayStr string) error { - key, value, err := readAuth(displayStr) - if err != nil { - return err - } - // Assume that the authentication protocol is "MIT-MAGIC-COOKIE-1". - if len(key) != 18 || len(value) != 16 { - return errors.New("unsupported Xauth") - } - // 0x006c means little-endian. 0x000b, 0x0000 means X major version 11, minor version 0. - // 0x0012 and 0x0010 means the auth key and value have lengths 18 and 16. - // The final 0x0000 is padding, so that the string length is a multiple of 4. - _, err = io.WriteString(w, "\x6c\x00\x0b\x00\x00\x00\x12\x00\x10\x00\x00\x00") - if err != nil { - return err - } - _, err = io.WriteString(w, key) - if err != nil { - return err - } - // Again, the 0x0000 is padding. - _, err = io.WriteString(w, "\x00\x00") - if err != nil { - return err - } - _, err = io.WriteString(w, value) - if err != nil { - return err - } - err = w.Flush() - if err != nil { - return err - } - return nil -} - -// readU8 reads a uint8 from r, using b as a scratch buffer. -func readU8(r io.Reader, b []byte) (uint8, error) { - _, err := io.ReadFull(r, b[:1]) - if err != nil { - return 0, err - } - return uint8(b[0]), nil -} - -// readU16LE reads a little-endian uint16 from r, using b as a scratch buffer. -func readU16LE(r io.Reader, b []byte) (uint16, error) { - _, err := io.ReadFull(r, b[:2]) - if err != nil { - return 0, err - } - return uint16(b[0]) | uint16(b[1])<<8, nil -} - -// readU32LE reads a little-endian uint32 from r, using b as a scratch buffer. -func readU32LE(r io.Reader, b []byte) (uint32, error) { - _, err := io.ReadFull(r, b[:4]) - if err != nil { - return 0, err - } - return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24, nil -} - -// setU32LE sets b[:4] to be the little-endian representation of u. -func setU32LE(b []byte, u uint32) { - b[0] = byte((u >> 0) & 0xff) - b[1] = byte((u >> 8) & 0xff) - b[2] = byte((u >> 16) & 0xff) - b[3] = byte((u >> 24) & 0xff) -} - -// checkPixmapFormats checks that we have an agreeable X pixmap Format. -func checkPixmapFormats(r io.Reader, b []byte, n int) (agree bool, err error) { - for i := 0; i < n; i++ { - _, err = io.ReadFull(r, b[:8]) - if err != nil { - return - } - // Byte 0 is depth, byte 1 is bits-per-pixel, byte 2 is scanline-pad, the rest (5) is padding. - if b[0] == 24 && b[1] == 32 { - agree = true - } - } - return -} - -// checkDepths checks that we have an agreeable X Depth (i.e. one that has an agreeable X VisualType). -func checkDepths(r io.Reader, b []byte, n int, visual uint32) (agree bool, err error) { - for i := 0; i < n; i++ { - var depth, visualsLen uint16 - depth, err = readU16LE(r, b) - if err != nil { - return - } - depth &= 0xff - visualsLen, err = readU16LE(r, b) - if err != nil { - return - } - // Ignore 4 bytes of padding. - _, err = io.ReadFull(r, b[:4]) - if err != nil { - return - } - for j := 0; j < int(visualsLen); j++ { - // Read 24 bytes: visual(4), class(1), bits per rgb value(1), colormap entries(2), - // red mask(4), green mask(4), blue mask(4), padding(4). - v, _ := readU32LE(r, b) - _, _ = readU32LE(r, b) - rm, _ := readU32LE(r, b) - gm, _ := readU32LE(r, b) - bm, _ := readU32LE(r, b) - _, err = readU32LE(r, b) - if err != nil { - return - } - if v == visual && rm == 0xff0000 && gm == 0xff00 && bm == 0xff && depth == 24 { - agree = true - } - } - } - return -} - -// checkScreens checks that we have an agreeable X Screen. -func checkScreens(r io.Reader, b []byte, n int) (root, visual uint32, err error) { - for i := 0; i < n; i++ { - var root0, visual0, x uint32 - root0, err = readU32LE(r, b) - if err != nil { - return - } - // Ignore the next 7x4 bytes, which is: colormap, whitepixel, blackpixel, current input masks, - // width and height (pixels), width and height (mm), min and max installed maps. - _, err = io.ReadFull(r, b[:28]) - if err != nil { - return - } - visual0, err = readU32LE(r, b) - if err != nil { - return - } - // Next 4 bytes: backing stores, save unders, root depth, allowed depths length. - x, err = readU32LE(r, b) - if err != nil { - return - } - nDepths := int(x >> 24) - var agree bool - agree, err = checkDepths(r, b, nDepths, visual0) - if err != nil { - return - } - if agree && root == 0 { - root = root0 - visual = visual0 - } - } - return -} - -// handshake performs the protocol handshake with the X server, and ensures -// that the server provides a compatible Screen, Depth, etc. -func (c *conn) handshake() error { - _, err := io.ReadFull(c.r, c.buf[:8]) - if err != nil { - return err - } - // Byte 0 should be 1 (success), bytes 2:6 should be 0xb0000000 (major/minor version 11.0). - if c.buf[0] != 1 || c.buf[2] != 11 || c.buf[3] != 0 || c.buf[4] != 0 || c.buf[5] != 0 { - return errors.New("unsupported X version") - } - // Ignore the release number. - _, err = io.ReadFull(c.r, c.buf[:4]) - if err != nil { - return err - } - // Read the resource ID base. - resourceIdBase, err := readU32LE(c.r, c.buf[:4]) - if err != nil { - return err - } - // Read the resource ID mask. - resourceIdMask, err := readU32LE(c.r, c.buf[:4]) - if err != nil { - return err - } - if resourceIdMask < 256 { - return errors.New("X resource ID mask is too small") - } - // Ignore the motion buffer size. - _, err = io.ReadFull(c.r, c.buf[:4]) - if err != nil { - return err - } - // Read the vendor length and round it up to a multiple of 4, - // for X11 protocol alignment reasons. - vendorLen, err := readU16LE(c.r, c.buf[:2]) - if err != nil { - return err - } - vendorLen = (vendorLen + 3) &^ 3 - // Read the maximum request length. - maxReqLen, err := readU16LE(c.r, c.buf[:2]) - if err != nil { - return err - } - if maxReqLen != 0xffff { - return errors.New("unsupported X maximum request length") - } - // Read the roots length. - rootsLen, err := readU8(c.r, c.buf[:1]) - if err != nil { - return err - } - // Read the pixmap formats length. - pixmapFormatsLen, err := readU8(c.r, c.buf[:1]) - if err != nil { - return err - } - // Ignore some things that we don't care about (totaling 10 + vendorLen bytes): - // imageByteOrder(1), bitmapFormatBitOrder(1), bitmapFormatScanlineUnit(1) bitmapFormatScanlinePad(1), - // minKeycode(1), maxKeycode(1), padding(4), vendor (vendorLen). - if 10+int(vendorLen) > cap(c.buf) { - return errors.New("unsupported X vendor") - } - _, err = io.ReadFull(c.r, c.buf[:10+int(vendorLen)]) - if err != nil { - return err - } - // Check that we have an agreeable pixmap format. - agree, err := checkPixmapFormats(c.r, c.buf[:8], int(pixmapFormatsLen)) - if err != nil { - return err - } - if !agree { - return errors.New("unsupported X pixmap formats") - } - // Check that we have an agreeable screen. - root, visual, err := checkScreens(c.r, c.buf[:24], int(rootsLen)) - if err != nil { - return err - } - if root == 0 || visual == 0 { - return errors.New("unsupported X screen") - } - c.gc = resID(resourceIdBase) - c.window = resID(resourceIdBase + 1) - c.root = resID(root) - c.visual = resID(visual) - return nil -} - -// NewWindow calls NewWindowDisplay with $DISPLAY. -func NewWindow() (gui.Window, error) { - display := os.Getenv("DISPLAY") - if len(display) == 0 { - return nil, errors.New("$DISPLAY not set") - } - return NewWindowDisplay(display) -} - -// NewWindowDisplay returns a new gui.Window, backed by a newly created and -// mapped X11 window. The X server to connect to is specified by the display -// string, such as ":1". -func NewWindowDisplay(display string) (gui.Window, error) { - socket, displayStr, err := connect(display) - if err != nil { - return nil, err - } - c := new(conn) - c.c = socket - c.r = bufio.NewReader(socket) - c.w = bufio.NewWriter(socket) - err = authenticate(c.w, displayStr) - if err != nil { - return nil, err - } - err = c.handshake() - if err != nil { - return nil, err - } - - // Now that we're connected, show a window, via three X protocol messages. - // First, issue a GetKeyboardMapping request. This is the first request, and - // will be associated with a cookie of 1. - setU32LE(c.buf[0:4], 0x00020065) // 0x65 is the GetKeyboardMapping opcode, and the message is 2 x 4 bytes long. - setU32LE(c.buf[4:8], uint32((keymapHi-keymapLo+1)<<8|keymapLo)) - // Second, create a graphics context (GC). - setU32LE(c.buf[8:12], 0x00060037) // 0x37 is the CreateGC opcode, and the message is 6 x 4 bytes long. - setU32LE(c.buf[12:16], uint32(c.gc)) - setU32LE(c.buf[16:20], uint32(c.root)) - setU32LE(c.buf[20:24], 0x00010004) // Bit 2 is XCB_GC_FOREGROUND, bit 16 is XCB_GC_GRAPHICS_EXPOSURES. - setU32LE(c.buf[24:28], 0x00000000) // The Foreground is black. - setU32LE(c.buf[28:32], 0x00000000) // GraphicsExposures' value is unused. - // Third, create the window. - setU32LE(c.buf[32:36], 0x000a0001) // 0x01 is the CreateWindow opcode, and the message is 10 x 4 bytes long. - setU32LE(c.buf[36:40], uint32(c.window)) - setU32LE(c.buf[40:44], uint32(c.root)) - setU32LE(c.buf[44:48], 0x00000000) // Initial (x, y) is (0, 0). - setU32LE(c.buf[48:52], windowHeight<<16|windowWidth) - setU32LE(c.buf[52:56], 0x00010000) // Border width is 0, XCB_WINDOW_CLASS_INPUT_OUTPUT is 1. - setU32LE(c.buf[56:60], uint32(c.visual)) - setU32LE(c.buf[60:64], 0x00000802) // Bit 1 is XCB_CW_BACK_PIXEL, bit 11 is XCB_CW_EVENT_MASK. - setU32LE(c.buf[64:68], 0x00000000) // The Back-Pixel is black. - setU32LE(c.buf[68:72], 0x0000804f) // Key/button press and release, pointer motion, and expose event masks. - // Fourth, map the window. - setU32LE(c.buf[72:76], 0x00020008) // 0x08 is the MapWindow opcode, and the message is 2 x 4 bytes long. - setU32LE(c.buf[76:80], uint32(c.window)) - // Write the bytes. - _, err = c.w.Write(c.buf[:80]) - if err != nil { - return nil, err - } - err = c.w.Flush() - if err != nil { - return nil, err - } - - c.img = image.NewRGBA(image.Rect(0, 0, windowWidth, windowHeight)) - c.eventc = make(chan interface{}, 16) - c.flush = make(chan bool, 1) - go c.readSocket() - go c.writeSocket() - return c, nil -} diff --git a/libgo/go/exp/sql/driver/driver.go b/libgo/go/exp/sql/driver/driver.go index 91a388421d1..f0bcca29106 100644 --- a/libgo/go/exp/sql/driver/driver.go +++ b/libgo/go/exp/sql/driver/driver.go @@ -7,7 +7,7 @@ // // Code simply using databases should use package sql. // -// Drivers only need to be aware of a subset of Go's types. The db package +// 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 @@ -94,12 +94,35 @@ type Result interface { // 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. - // -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 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 diff --git a/libgo/go/exp/sql/fakedb_test.go b/libgo/go/exp/sql/fakedb_test.go index 17028e2cc38..2474a86f644 100644 --- a/libgo/go/exp/sql/fakedb_test.go +++ b/libgo/go/exp/sql/fakedb_test.go @@ -90,6 +90,8 @@ type fakeStmt struct { 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) @@ -232,6 +234,9 @@ func (c *fakeConn) prepareSelect(stmt *fakeStmt, parts []string) (driver.Stmt, e 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) @@ -342,10 +347,16 @@ func (s *fakeStmt) ColumnConverter(idx int) driver.ValueConverter { } func (s *fakeStmt) Close() error { + 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 @@ -405,6 +416,9 @@ func (s *fakeStmt) execInsert(args []interface{}) (driver.Result, error) { } func (s *fakeStmt) Query(args []interface{}) (driver.Rows, error) { + if s.closed { + return nil, errClosed + } err := checkSubsetTypes(args) if err != nil { return nil, err diff --git a/libgo/go/exp/sql/sql.go b/libgo/go/exp/sql/sql.go index c055fdd68c6..f17d12eaa13 100644 --- a/libgo/go/exp/sql/sql.go +++ b/libgo/go/exp/sql/sql.go @@ -344,25 +344,26 @@ func (tx *Tx) Rollback() error { return tx.txi.Rollback() } -// Prepare creates a prepared statement. +// Prepare creates a prepared statement for use within a transaction. // -// The statement is only valid within the scope of this 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): the restriction that the returned statement - // is only valid for this Transaction is lame and negates a - // lot of the benefit of prepared statements. 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. + // 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 @@ -383,6 +384,39 @@ func (tx *Tx) Prepare(query string) (*Stmt, error) { 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) { @@ -448,8 +482,9 @@ type connStmt struct { // 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 Sttm + 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 @@ -513,6 +548,9 @@ func (s *Stmt) Exec(args ...interface{}) (Result, error) { // 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 s.stickyErr != nil { + return nil, nil, nil, s.stickyErr + } s.mu.Lock() if s.closed { s.mu.Unlock() @@ -621,6 +659,9 @@ func (s *Stmt) QueryRow(args ...interface{}) *Row { // 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 { diff --git a/libgo/go/exp/sql/sql_test.go b/libgo/go/exp/sql/sql_test.go index d365f6ba190..4f8318d26ef 100644 --- a/libgo/go/exp/sql/sql_test.go +++ b/libgo/go/exp/sql/sql_test.go @@ -5,6 +5,7 @@ package sql import ( + "reflect" "strings" "testing" ) @@ -22,7 +23,6 @@ func newTestDB(t *testing.T, name string) *DB { exec(t, db, "INSERT|people|name=Alice,age=?", 1) exec(t, db, "INSERT|people|name=Bob,age=?", 2) exec(t, db, "INSERT|people|name=Chris,age=?", 3) - } return db } @@ -42,6 +42,40 @@ func closeDB(t *testing.T, db *DB) { } 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) + } +} + +func TestQueryRow(t *testing.T) { db := newTestDB(t, "people") defer closeDB(t, db) var name string @@ -75,6 +109,24 @@ func TestQuery(t *testing.T) { } } +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) @@ -114,7 +166,7 @@ func TestBogusPreboundParameters(t *testing.T) { } } -func TestDb(t *testing.T) { +func TestExec(t *testing.T) { db := newTestDB(t, "foo") defer closeDB(t, db) exec(t, db, "CREATE|t1|name=string,age=int32,dead=bool") @@ -154,3 +206,25 @@ func TestDb(t *testing.T) { } } } + +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) + } +} diff --git a/libgo/go/exp/ssh/channel.go b/libgo/go/exp/ssh/channel.go index 6ff8203ce27..9d75f37de74 100644 --- a/libgo/go/exp/ssh/channel.go +++ b/libgo/go/exp/ssh/channel.go @@ -244,13 +244,13 @@ func (c *channel) Write(data []byte) (n int, err error) { packet := make([]byte, 1+4+4+len(todo)) packet[0] = msgChannelData - packet[1] = byte(c.theirId) >> 24 - packet[2] = byte(c.theirId) >> 16 - packet[3] = byte(c.theirId) >> 8 + packet[1] = byte(c.theirId >> 24) + packet[2] = byte(c.theirId >> 16) + packet[3] = byte(c.theirId >> 8) packet[4] = byte(c.theirId) - packet[5] = byte(len(todo)) >> 24 - packet[6] = byte(len(todo)) >> 16 - packet[7] = byte(len(todo)) >> 8 + packet[5] = byte(len(todo) >> 24) + packet[6] = byte(len(todo) >> 16) + packet[7] = byte(len(todo) >> 8) packet[8] = byte(len(todo)) copy(packet[9:], todo) diff --git a/libgo/go/exp/ssh/client.go b/libgo/go/exp/ssh/client.go index 24569ad9389..429dee975bc 100644 --- a/libgo/go/exp/ssh/client.go +++ b/libgo/go/exp/ssh/client.go @@ -172,40 +172,12 @@ func (c *ClientConn) kexDH(group *dhGroup, hashFunc crypto.Hash, magics *handsha marshalInt(K, kInt) h.Write(K) - H := h.Sum() + H := h.Sum(nil) return H, K, nil } -// openChan opens a new client channel. The most common session type is "session". -// The full set of valid session types are listed in RFC 4250 4.9.1. -func (c *ClientConn) openChan(typ string) (*clientChan, error) { - ch := c.newChan(c.transport) - if err := c.writePacket(marshal(msgChannelOpen, channelOpenMsg{ - ChanType: typ, - PeersId: ch.id, - PeersWindow: 1 << 14, - MaxPacketSize: 1 << 15, // RFC 4253 6.1 - })); err != nil { - c.chanlist.remove(ch.id) - return nil, err - } - // wait for response - switch msg := (<-ch.msg).(type) { - case *channelOpenConfirmMsg: - ch.peersId = msg.MyId - ch.win <- int(msg.MyWindow) - case *channelOpenFailureMsg: - c.chanlist.remove(ch.id) - return nil, errors.New(msg.Message) - default: - c.chanlist.remove(ch.id) - return nil, errors.New("Unexpected packet") - } - return ch, nil -} - -// mainloop reads incoming messages and routes channel messages +// mainLoop reads incoming messages and routes channel messages // to their respective ClientChans. func (c *ClientConn) mainLoop() { // TODO(dfc) signal the underlying close to all channels @@ -271,7 +243,7 @@ func (c *ClientConn) mainLoop() { case *windowAdjustMsg: c.getChan(msg.PeersId).win <- int(msg.AdditionalBytes) default: - fmt.Printf("mainLoop: unhandled %#v\n", msg) + fmt.Printf("mainLoop: unhandled message %T: %v\n", msg, msg) } } } @@ -338,27 +310,16 @@ func newClientChan(t *transport, id uint32) *clientChan { // Close closes the channel. This does not close the underlying connection. func (c *clientChan) Close() error { return c.writePacket(marshal(msgChannelClose, channelCloseMsg{ - PeersId: c.id, + PeersId: c.peersId, })) } -func (c *clientChan) sendChanReq(req channelRequestMsg) error { - if err := c.writePacket(marshal(msgChannelRequest, req)); err != nil { - return err - } - msg := <-c.msg - if _, ok := msg.(*channelRequestSuccessMsg); ok { - return nil - } - return fmt.Errorf("failed to complete request: %s, %#v", req.Request, msg) -} - // Thread safe channel list. type chanlist struct { // protects concurrent access to chans sync.Mutex // chans are indexed by the local id of the channel, clientChan.id. - // The PeersId value of messages received by ClientConn.mainloop is + // The PeersId value of messages received by ClientConn.mainLoop is // used to locate the right local clientChan in this slice. chans []*clientChan } @@ -395,7 +356,7 @@ func (c *chanlist) remove(id uint32) { // A chanWriter represents the stdin of a remote process. type chanWriter struct { win chan int // receives window adjustments - id uint32 // this channel's id + peersId uint32 // the peer's id rwin int // current rwin size packetWriter // for sending channelDataMsg } @@ -414,8 +375,8 @@ func (w *chanWriter) Write(data []byte) (n int, err error) { n = len(data) packet := make([]byte, 0, 9+n) packet = append(packet, msgChannelData, - byte(w.id)>>24, byte(w.id)>>16, byte(w.id)>>8, byte(w.id), - byte(n)>>24, byte(n)>>16, byte(n)>>8, byte(n)) + byte(w.peersId>>24), byte(w.peersId>>16), byte(w.peersId>>8), byte(w.peersId), + byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) err = w.writePacket(append(packet, data...)) w.rwin -= n return @@ -424,7 +385,7 @@ func (w *chanWriter) Write(data []byte) (n int, err error) { } func (w *chanWriter) Close() error { - return w.writePacket(marshal(msgChannelEOF, channelEOFMsg{w.id})) + return w.writePacket(marshal(msgChannelEOF, channelEOFMsg{w.peersId})) } // A chanReader represents stdout or stderr of a remote process. @@ -433,8 +394,8 @@ type chanReader struct { // If writes to this channel block, they will block mainLoop, making // it unable to receive new messages from the remote side. data chan []byte // receives data from remote - id uint32 - packetWriter // for sending windowAdjustMsg + peersId uint32 // the peer's id + packetWriter // for sending windowAdjustMsg buf []byte } @@ -446,7 +407,7 @@ func (r *chanReader) Read(data []byte) (int, error) { n := copy(data, r.buf) r.buf = r.buf[n:] msg := windowAdjustMsg{ - PeersId: r.id, + PeersId: r.peersId, AdditionalBytes: uint32(n), } return n, r.writePacket(marshal(msgChannelWindowAdjust, msg)) @@ -458,7 +419,3 @@ func (r *chanReader) Read(data []byte) (int, error) { } panic("unreachable") } - -func (r *chanReader) Close() error { - return r.writePacket(marshal(msgChannelEOF, channelEOFMsg{r.id})) -} diff --git a/libgo/go/exp/ssh/client_auth_test.go b/libgo/go/exp/ssh/client_auth_test.go index 6467f578356..4ef9213a9cd 100644 --- a/libgo/go/exp/ssh/client_auth_test.go +++ b/libgo/go/exp/ssh/client_auth_test.go @@ -70,7 +70,7 @@ func (k *keychain) Sign(i int, rand io.Reader, data []byte) (sig []byte, err err hashFunc := crypto.SHA1 h := hashFunc.New() h.Write(data) - digest := h.Sum() + digest := h.Sum(nil) return rsa.SignPKCS1v15(rand, k.keys[i], hashFunc, digest) } diff --git a/libgo/go/exp/ssh/common.go b/libgo/go/exp/ssh/common.go index 01c55219d47..6844fb89b79 100644 --- a/libgo/go/exp/ssh/common.go +++ b/libgo/go/exp/ssh/common.go @@ -224,3 +224,16 @@ func buildDataSignedForAuth(sessionId []byte, req userAuthRequestMsg, algo, pubK r = marshalString(r, pubKey) return ret } + +// safeString sanitises s according to RFC 4251, section 9.2. +// All control characters except tab, carriage return and newline are +// replaced by 0x20. +func safeString(s string) string { + out := []byte(s) + for i, c := range out { + if c < 0x20 && c != 0xd && c != 0xa && c != 0x9 { + out[i] = 0x20 + } + } + return string(out) +} diff --git a/libgo/go/exp/ssh/common_test.go b/libgo/go/exp/ssh/common_test.go new file mode 100644 index 00000000000..2f4448a1bd4 --- /dev/null +++ b/libgo/go/exp/ssh/common_test.go @@ -0,0 +1,26 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +import ( + "testing" +) + +var strings = map[string]string{ + "\x20\x0d\x0a": "\x20\x0d\x0a", + "flibble": "flibble", + "new\x20line": "new\x20line", + "123456\x07789": "123456 789", + "\t\t\x10\r\n": "\t\t \r\n", +} + +func TestSafeString(t *testing.T) { + for s, expected := range strings { + actual := safeString(s) + if expected != actual { + t.Errorf("expected: %v, actual: %v", []byte(expected), []byte(actual)) + } + } +} diff --git a/libgo/go/exp/ssh/doc.go b/libgo/go/exp/ssh/doc.go index 248b2fec4f8..480f877191a 100644 --- a/libgo/go/exp/ssh/doc.go +++ b/libgo/go/exp/ssh/doc.go @@ -92,9 +92,9 @@ Each ClientConn can support multiple interactive sessions, represented by a Sess session, err := client.NewSession() Once a Session is created, you can execute a single command on the remote side -using the Exec method. +using the Run method. - if err := session.Exec("/usr/bin/whoami"); err != nil { + if err := session.Run("/usr/bin/whoami"); err != nil { panic("Failed to exec: " + err.String()) } reader := bufio.NewReader(session.Stdin) diff --git a/libgo/go/exp/ssh/server.go b/libgo/go/exp/ssh/server.go index 428a747e1e0..1eee9a4a977 100644 --- a/libgo/go/exp/ssh/server.go +++ b/libgo/go/exp/ssh/server.go @@ -207,11 +207,11 @@ func (s *ServerConn) kexDH(group *dhGroup, hashFunc crypto.Hash, magics *handsha marshalInt(K, kInt) h.Write(K) - H = h.Sum() + H = h.Sum(nil) h.Reset() h.Write(H) - hh := h.Sum() + hh := h.Sum(nil) var sig []byte switch hostKeyAlgo { @@ -478,7 +478,7 @@ userAuthLoop: hashFunc := crypto.SHA1 h := hashFunc.New() h.Write(signedData) - digest := h.Sum() + digest := h.Sum(nil) rsaKey, ok := parseRSA(pubKey) if !ok { return ParseError{msgUserAuthRequest} diff --git a/libgo/go/exp/ssh/session.go b/libgo/go/exp/ssh/session.go index 77154f2c3c3..5f98a8d58c6 100644 --- a/libgo/go/exp/ssh/session.go +++ b/libgo/go/exp/ssh/session.go @@ -8,125 +8,409 @@ package ssh // "RFC 4254, section 6". import ( - "encoding/binary" + "bytes" "errors" + "fmt" "io" + "io/ioutil" +) + +type Signal string + +// POSIX signals as listed in RFC 4254 Section 6.10. +const ( + SIGABRT Signal = "ABRT" + SIGALRM Signal = "ALRM" + SIGFPE Signal = "FPE" + SIGHUP Signal = "HUP" + SIGILL Signal = "ILL" + SIGINT Signal = "INT" + SIGKILL Signal = "KILL" + SIGPIPE Signal = "PIPE" + SIGQUIT Signal = "QUIT" + SIGSEGV Signal = "SEGV" + SIGTERM Signal = "TERM" + SIGUSR1 Signal = "USR1" + SIGUSR2 Signal = "USR2" ) // A Session represents a connection to a remote command or shell. type Session struct { - // Writes to Stdin are made available to the remote command's standard input. - // Closing Stdin causes the command to observe an EOF on its standard input. - Stdin io.WriteCloser + // Stdin specifies the remote process's standard input. + // If Stdin is nil, the remote process reads from an empty + // bytes.Buffer. + Stdin io.Reader - // Reads from Stdout and Stderr consume from the remote command's standard - // output and error streams, respectively. - // There is a fixed amount of buffering that is shared for the two streams. - // Failing to read from either may eventually cause the command to block. - // Closing Stdout unblocks such writes and causes them to return errors. - Stdout io.ReadCloser - Stderr io.Reader + // Stdout and Stderr specify the remote process's standard + // output and error. + // + // If either is nil, Run connects the corresponding file + // descriptor to an instance of ioutil.Discard. There is a + // fixed amount of buffering that is shared for the two streams. + // If either blocks it may eventually cause the remote + // command to block. + Stdout io.Writer + Stderr io.Writer *clientChan // the channel backing this session - started bool // started is set to true once a Shell or Exec is invoked. + started bool // true once Start, Run or Shell is invoked. + closeAfterWait []io.Closer + copyFuncs []func() error + errch chan error // one send per copyFunc +} + +// RFC 4254 Section 6.4. +type setenvRequest struct { + PeersId uint32 + Request string + WantReply bool + Name string + Value string } // Setenv sets an environment variable that will be applied to any -// command executed by Shell or Exec. +// command executed by Shell or Run. func (s *Session) Setenv(name, value string) error { - n, v := []byte(name), []byte(value) - nlen, vlen := stringLength(n), stringLength(v) - payload := make([]byte, nlen+vlen) - marshalString(payload[:nlen], n) - marshalString(payload[nlen:], v) - - return s.sendChanReq(channelRequestMsg{ - PeersId: s.id, - Request: "env", - WantReply: true, - RequestSpecificData: payload, - }) + req := setenvRequest{ + PeersId: s.peersId, + Request: "env", + WantReply: true, + Name: name, + Value: value, + } + if err := s.writePacket(marshal(msgChannelRequest, req)); err != nil { + return err + } + return s.waitForResponse() } -// An empty mode list (a string of 1 character, opcode 0), see RFC 4254 Section 8. -var emptyModeList = []byte{0, 0, 0, 1, 0} +// An empty mode list, see RFC 4254 Section 8. +var emptyModelist = "\x00" + +// RFC 4254 Section 6.2. +type ptyRequestMsg struct { + PeersId uint32 + Request string + WantReply bool + Term string + Columns uint32 + Rows uint32 + Width uint32 + Height uint32 + Modelist string +} // RequestPty requests the association of a pty with the session on the remote host. func (s *Session) RequestPty(term string, h, w int) error { - buf := make([]byte, 4+len(term)+16+len(emptyModeList)) - b := marshalString(buf, []byte(term)) - binary.BigEndian.PutUint32(b, uint32(h)) - binary.BigEndian.PutUint32(b[4:], uint32(w)) - binary.BigEndian.PutUint32(b[8:], uint32(h*8)) - binary.BigEndian.PutUint32(b[12:], uint32(w*8)) - copy(b[16:], emptyModeList) - - return s.sendChanReq(channelRequestMsg{ - PeersId: s.id, - Request: "pty-req", - WantReply: true, - RequestSpecificData: buf, - }) -} - -// Exec runs cmd on the remote host. Typically, the remote -// server passes cmd to the shell for interpretation. -// A Session only accepts one call to Exec or Shell. -func (s *Session) Exec(cmd string) error { - if s.started { - return errors.New("session already started") + req := ptyRequestMsg{ + PeersId: s.peersId, + Request: "pty-req", + WantReply: true, + Term: term, + Columns: uint32(w), + Rows: uint32(h), + Width: uint32(w * 8), + Height: uint32(h * 8), + Modelist: emptyModelist, } - cmdLen := stringLength([]byte(cmd)) - payload := make([]byte, cmdLen) - marshalString(payload, []byte(cmd)) - s.started = true - - return s.sendChanReq(channelRequestMsg{ - PeersId: s.id, - Request: "exec", - WantReply: true, - RequestSpecificData: payload, - }) + if err := s.writePacket(marshal(msgChannelRequest, req)); err != nil { + return err + } + return s.waitForResponse() } -// Shell starts a login shell on the remote host. A Session only -// accepts one call to Exec or Shell. +// RFC 4254 Section 6.9. +type signalMsg struct { + PeersId uint32 + Request string + WantReply bool + Signal string +} + +// Signal sends the given signal to the remote process. +// sig is one of the SIG* constants. +func (s *Session) Signal(sig Signal) error { + req := signalMsg{ + PeersId: s.peersId, + Request: "signal", + WantReply: false, + Signal: string(sig), + } + return s.writePacket(marshal(msgChannelRequest, req)) +} + +// RFC 4254 Section 6.5. +type execMsg struct { + PeersId uint32 + Request string + WantReply bool + Command string +} + +// Start runs cmd on the remote host. Typically, the remote +// server passes cmd to the shell for interpretation. +// A Session only accepts one call to Run, Start or Shell. +func (s *Session) Start(cmd string) error { + if s.started { + return errors.New("ssh: session already started") + } + req := execMsg{ + PeersId: s.peersId, + Request: "exec", + WantReply: true, + Command: cmd, + } + if err := s.writePacket(marshal(msgChannelRequest, req)); err != nil { + return err + } + if err := s.waitForResponse(); err != nil { + return fmt.Errorf("ssh: could not execute command %s: %v", cmd, err) + } + return s.start() +} + +// Run runs cmd on the remote host and waits for it to terminate. +// Typically, the remote server passes cmd to the shell for +// interpretation. A Session only accepts one call to Run, +// Start or Shell. +func (s *Session) Run(cmd string) error { + err := s.Start(cmd) + if err != nil { + return err + } + return s.Wait() +} + +// Shell starts a login shell on the remote host. A Session only +// accepts one call to Run, Start or Shell. func (s *Session) Shell() error { if s.started { - return errors.New("session already started") + return errors.New("ssh: session already started") } - s.started = true - - return s.sendChanReq(channelRequestMsg{ - PeersId: s.id, + req := channelRequestMsg{ + PeersId: s.peersId, Request: "shell", WantReply: true, - }) + } + if err := s.writePacket(marshal(msgChannelRequest, req)); err != nil { + return err + } + if err := s.waitForResponse(); err != nil { + return fmt.Errorf("ssh: cound not execute shell: %v", err) + } + return s.start() } +func (s *Session) waitForResponse() error { + msg := <-s.msg + switch msg.(type) { + case *channelRequestSuccessMsg: + return nil + case *channelRequestFailureMsg: + return errors.New("request failed") + } + return fmt.Errorf("unknown packet %T received: %v", msg, msg) +} + +func (s *Session) start() error { + s.started = true + + type F func(*Session) error + for _, setupFd := range []F{(*Session).stdin, (*Session).stdout, (*Session).stderr} { + if err := setupFd(s); err != nil { + return err + } + } + + s.errch = make(chan error, len(s.copyFuncs)) + for _, fn := range s.copyFuncs { + go func(fn func() error) { + s.errch <- fn() + }(fn) + } + return nil +} + +// Wait waits for the remote command to exit. +func (s *Session) Wait() error { + if !s.started { + return errors.New("ssh: session not started") + } + waitErr := s.wait() + + var copyError error + for _ = range s.copyFuncs { + if err := <-s.errch; err != nil && copyError == nil { + copyError = err + } + } + for _, fd := range s.closeAfterWait { + fd.Close() + } + if waitErr != nil { + return waitErr + } + return copyError +} + +func (s *Session) wait() error { + for { + switch msg := (<-s.msg).(type) { + case *channelRequestMsg: + // TODO(dfc) improve this behavior to match os.Waitmsg + switch msg.Request { + case "exit-status": + d := msg.RequestSpecificData + status := int(d[0])<<24 | int(d[1])<<16 | int(d[2])<<8 | int(d[3]) + if status > 0 { + return fmt.Errorf("remote process exited with %d", status) + } + return nil + case "exit-signal": + // TODO(dfc) make a more readable error message + return fmt.Errorf("%v", msg.RequestSpecificData) + default: + return fmt.Errorf("wait: unexpected channel request: %v", msg) + } + default: + return fmt.Errorf("wait: unexpected packet %T received: %v", msg, msg) + } + } + panic("unreachable") +} + +func (s *Session) stdin() error { + if s.Stdin == nil { + s.Stdin = new(bytes.Buffer) + } + s.copyFuncs = append(s.copyFuncs, func() error { + w := &chanWriter{ + packetWriter: s, + peersId: s.peersId, + win: s.win, + } + _, err := io.Copy(w, s.Stdin) + if err1 := w.Close(); err == nil { + err = err1 + } + return err + }) + return nil +} + +func (s *Session) stdout() error { + if s.Stdout == nil { + s.Stdout = ioutil.Discard + } + s.copyFuncs = append(s.copyFuncs, func() error { + r := &chanReader{ + packetWriter: s, + peersId: s.peersId, + data: s.data, + } + _, err := io.Copy(s.Stdout, r) + return err + }) + return nil +} + +func (s *Session) stderr() error { + if s.Stderr == nil { + s.Stderr = ioutil.Discard + } + s.copyFuncs = append(s.copyFuncs, func() error { + r := &chanReader{ + packetWriter: s, + peersId: s.peersId, + data: s.dataExt, + } + _, err := io.Copy(s.Stderr, r) + return err + }) + return nil +} + +// StdinPipe returns a pipe that will be connected to the +// remote command's standard input when the command starts. +func (s *Session) StdinPipe() (io.WriteCloser, error) { + if s.Stdin != nil { + return nil, errors.New("ssh: Stdin already set") + } + if s.started { + return nil, errors.New("ssh: StdinPipe after process started") + } + pr, pw := io.Pipe() + s.Stdin = pr + s.closeAfterWait = append(s.closeAfterWait, pr) + return pw, nil +} + +// StdoutPipe returns a pipe that will be connected to the +// remote command's standard output when the command starts. +// There is a fixed amount of buffering that is shared between +// stdout and stderr streams. If the StdoutPipe reader is +// not serviced fast enought it may eventually cause the +// remote command to block. +func (s *Session) StdoutPipe() (io.ReadCloser, error) { + if s.Stdout != nil { + return nil, errors.New("ssh: Stdout already set") + } + if s.started { + return nil, errors.New("ssh: StdoutPipe after process started") + } + pr, pw := io.Pipe() + s.Stdout = pw + s.closeAfterWait = append(s.closeAfterWait, pw) + return pr, nil +} + +// StderrPipe returns a pipe that will be connected to the +// remote command's standard error when the command starts. +// There is a fixed amount of buffering that is shared between +// stdout and stderr streams. If the StderrPipe reader is +// not serviced fast enought it may eventually cause the +// remote command to block. +func (s *Session) StderrPipe() (io.ReadCloser, error) { + if s.Stderr != nil { + return nil, errors.New("ssh: Stderr already set") + } + if s.started { + return nil, errors.New("ssh: StderrPipe after process started") + } + pr, pw := io.Pipe() + s.Stderr = pw + s.closeAfterWait = append(s.closeAfterWait, pw) + return pr, nil +} + +// TODO(dfc) add Output and CombinedOutput helpers + // NewSession returns a new interactive session on the remote host. func (c *ClientConn) NewSession() (*Session, error) { - ch, err := c.openChan("session") - if err != nil { + ch := c.newChan(c.transport) + if err := c.writePacket(marshal(msgChannelOpen, channelOpenMsg{ + ChanType: "session", + PeersId: ch.id, + PeersWindow: 1 << 14, + MaxPacketSize: 1 << 15, // RFC 4253 6.1 + })); err != nil { + c.chanlist.remove(ch.id) return nil, err } - return &Session{ - Stdin: &chanWriter{ - packetWriter: ch, - id: ch.id, - win: ch.win, - }, - Stdout: &chanReader{ - packetWriter: ch, - id: ch.id, - data: ch.data, - }, - Stderr: &chanReader{ - packetWriter: ch, - id: ch.id, - data: ch.dataExt, - }, - clientChan: ch, - }, nil + // wait for response + msg := <-ch.msg + switch msg := msg.(type) { + case *channelOpenConfirmMsg: + ch.peersId = msg.MyId + ch.win <- int(msg.MyWindow) + return &Session{ + clientChan: ch, + }, nil + case *channelOpenFailureMsg: + c.chanlist.remove(ch.id) + return nil, fmt.Errorf("ssh: channel open failed: %s", msg.Message) + } + c.chanlist.remove(ch.id) + return nil, fmt.Errorf("ssh: unexpected message %T: %v", msg, msg) } diff --git a/libgo/go/exp/ssh/session_test.go b/libgo/go/exp/ssh/session_test.go new file mode 100644 index 00000000000..4be7746d17e --- /dev/null +++ b/libgo/go/exp/ssh/session_test.go @@ -0,0 +1,149 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +// Session tests. + +import ( + "bytes" + "io" + "testing" +) + +// dial constructs a new test server and returns a *ClientConn. +func dial(t *testing.T) *ClientConn { + pw := password("tiger") + serverConfig.PasswordCallback = func(user, pass string) bool { + return user == "testuser" && pass == string(pw) + } + serverConfig.PubKeyCallback = nil + + l, err := Listen("tcp", "127.0.0.1:0", serverConfig) + if err != nil { + t.Fatalf("unable to listen: %s", err) + } + go func() { + defer l.Close() + conn, err := l.Accept() + if err != nil { + t.Errorf("Unable to accept: %v", err) + return + } + defer conn.Close() + if err := conn.Handshake(); err != nil { + t.Errorf("Unable to handshake: %v", err) + return + } + for { + ch, err := conn.Accept() + if err == io.EOF { + return + } + if err != nil { + t.Errorf("Unable to accept incoming channel request: %v", err) + return + } + if ch.ChannelType() != "session" { + ch.Reject(UnknownChannelType, "unknown channel type") + continue + } + ch.Accept() + go func() { + defer ch.Close() + // this string is returned to stdout + shell := NewServerShell(ch, "golang") + shell.ReadLine() + type exitMsg struct { + PeersId uint32 + Request string + WantReply bool + Status uint32 + } + // TODO(dfc) casting to the concrete type should not be + // necessary to send a packet. + msg := exitMsg{ + PeersId: ch.(*channel).theirId, + Request: "exit-status", + WantReply: false, + Status: 0, + } + ch.(*channel).serverConn.writePacket(marshal(msgChannelRequest, msg)) + }() + } + t.Log("done") + }() + + config := &ClientConfig{ + User: "testuser", + Auth: []ClientAuth{ + ClientAuthPassword(pw), + }, + } + + c, err := Dial("tcp", l.Addr().String(), config) + if err != nil { + t.Fatalf("unable to dial remote side: %s", err) + } + return c +} + +// Test a simple string is returned to session.Stdout. +func TestSessionShell(t *testing.T) { + conn := dial(t) + defer conn.Close() + session, err := conn.NewSession() + if err != nil { + t.Fatalf("Unable to request new session: %s", err) + } + defer session.Close() + stdout := new(bytes.Buffer) + session.Stdout = stdout + if err := session.Shell(); err != nil { + t.Fatalf("Unable to execute command: %s", err) + } + if err := session.Wait(); err != nil { + t.Fatalf("Remote command did not exit cleanly: %s", err) + } + actual := stdout.String() + if actual != "golang" { + t.Fatalf("Remote shell did not return expected string: expected=golang, actual=%s", actual) + } +} + +// TODO(dfc) add support for Std{in,err}Pipe when the Server supports it. + +// Test a simple string is returned via StdoutPipe. +func TestSessionStdoutPipe(t *testing.T) { + conn := dial(t) + defer conn.Close() + session, err := conn.NewSession() + if err != nil { + t.Fatalf("Unable to request new session: %s", err) + } + defer session.Close() + stdout, err := session.StdoutPipe() + if err != nil { + t.Fatalf("Unable to request StdoutPipe(): %v", err) + } + var buf bytes.Buffer + if err := session.Shell(); err != nil { + t.Fatalf("Unable to execute command: %s", err) + } + done := make(chan bool, 1) + go func() { + if _, err := io.Copy(&buf, stdout); err != nil { + t.Errorf("Copy of stdout failed: %v", err) + } + done <- true + }() + if err := session.Wait(); err != nil { + t.Fatalf("Remote command did not exit cleanly: %s", err) + } + <-done + actual := buf.String() + if actual != "golang" { + t.Fatalf("Remote shell did not return expected string: expected=golang, actual=%s", actual) + } +} diff --git a/libgo/go/exp/ssh/tcpip.go b/libgo/go/exp/ssh/tcpip.go index 859dedc93b3..f3bbac5d19e 100644 --- a/libgo/go/exp/ssh/tcpip.go +++ b/libgo/go/exp/ssh/tcpip.go @@ -86,12 +86,12 @@ func (c *ClientConn) dial(laddr string, lport int, raddr string, rport int) (*tc clientChan: ch, Reader: &chanReader{ packetWriter: ch, - id: ch.id, + peersId: ch.peersId, data: ch.data, }, Writer: &chanWriter{ packetWriter: ch, - id: ch.id, + peersId: ch.peersId, win: ch.win, }, }, nil diff --git a/libgo/go/exp/ssh/tcpip_func_test.go b/libgo/go/exp/ssh/tcpip_func_test.go new file mode 100644 index 00000000000..261297241e9 --- /dev/null +++ b/libgo/go/exp/ssh/tcpip_func_test.go @@ -0,0 +1,59 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ssh + +// direct-tcpip functional tests + +import ( + "net" + "net/http" + "testing" +) + +func TestTCPIPHTTP(t *testing.T) { + if *sshuser == "" { + t.Log("ssh.user not defined, skipping test") + return + } + // google.com will generate at least one redirect, possibly three + // depending on your location. + doTest(t, "http://google.com") +} + +func TestTCPIPHTTPS(t *testing.T) { + if *sshuser == "" { + t.Log("ssh.user not defined, skipping test") + return + } + doTest(t, "https://encrypted.google.com/") +} + +func doTest(t *testing.T, url string) { + config := &ClientConfig{ + User: *sshuser, + Auth: []ClientAuth{ + ClientAuthPassword(password(*sshpass)), + }, + } + conn, err := Dial("tcp", "localhost:22", config) + if err != nil { + t.Fatalf("Unable to connect: %s", err) + } + defer conn.Close() + tr := &http.Transport{ + Dial: func(n, addr string) (net.Conn, error) { + return conn.Dial(n, addr) + }, + } + client := &http.Client{ + Transport: tr, + } + resp, err := client.Get(url) + if err != nil { + t.Fatalf("unable to proxy: %s", err) + } + // got a body without error + t.Log(resp) +} diff --git a/libgo/go/exp/ssh/transport.go b/libgo/go/exp/ssh/transport.go index b8cb2c319d8..bcd073e7ce6 100644 --- a/libgo/go/exp/ssh/transport.go +++ b/libgo/go/exp/ssh/transport.go @@ -123,7 +123,7 @@ func (r *reader) readOnePacket() ([]byte, error) { if r.mac != nil { r.mac.Write(packet[:length-1]) - if subtle.ConstantTimeCompare(r.mac.Sum(), mac) != 1 { + if subtle.ConstantTimeCompare(r.mac.Sum(nil), mac) != 1 { return nil, errors.New("ssh: MAC failure") } } @@ -201,7 +201,7 @@ func (w *writer) writePacket(packet []byte) error { } if w.mac != nil { - if _, err := w.Write(w.mac.Sum()); err != nil { + if _, err := w.Write(w.mac.Sum(nil)); err != nil { return err } } @@ -297,7 +297,7 @@ func generateKeyMaterial(out, tag []byte, K, H, sessionId []byte, h hash.Hash) { h.Write(digestsSoFar) } - digest := h.Sum() + digest := h.Sum(nil) n := copy(out, digest) out = out[n:] if len(out) > 0 { @@ -317,9 +317,9 @@ func (t truncatingMAC) Write(data []byte) (int, error) { return t.hmac.Write(data) } -func (t truncatingMAC) Sum() []byte { - digest := t.hmac.Sum() - return digest[:t.length] +func (t truncatingMAC) Sum(in []byte) []byte { + out := t.hmac.Sum(in) + return out[:len(in)+t.length] } func (t truncatingMAC) Reset() { diff --git a/libgo/go/exp/types/check_test.go b/libgo/go/exp/types/check_test.go index 4a30acf2315..35535ea406f 100644 --- a/libgo/go/exp/types/check_test.go +++ b/libgo/go/exp/types/check_test.go @@ -202,7 +202,7 @@ func TestCheck(t *testing.T) { // For easy debugging w/o changing the testing code, // if there is a local test file, only test that file. const testfile = "test.go" - if fi, err := os.Stat(testfile); err == nil && fi.IsRegular() { + if fi, err := os.Stat(testfile); err == nil && !fi.IsDir() { fmt.Printf("WARNING: Testing only %s (remove it to run all tests)\n", testfile) check(t, testfile, []string{testfile}) return diff --git a/libgo/go/exp/types/gcimporter.go b/libgo/go/exp/types/gcimporter.go index 4167caf3f0e..16a8667ff66 100644 --- a/libgo/go/exp/types/gcimporter.go +++ b/libgo/go/exp/types/gcimporter.go @@ -59,7 +59,7 @@ func findPkg(path string) (filename, id string) { // try extensions for _, ext := range pkgExts { filename = noext + ext - if f, err := os.Stat(filename); err == nil && f.IsRegular() { + if f, err := os.Stat(filename); err == nil && !f.IsDir() { return } } diff --git a/libgo/go/exp/types/gcimporter_test.go b/libgo/go/exp/types/gcimporter_test.go index 3f66d226153..7475d352209 100644 --- a/libgo/go/exp/types/gcimporter_test.go +++ b/libgo/go/exp/types/gcimporter_test.go @@ -58,32 +58,32 @@ func testPath(t *testing.T, path string) bool { return true } -const maxTime = 3e9 // maximum allotted testing time in ns +const maxTime = 3 * time.Second -func testDir(t *testing.T, dir string, endTime int64) (nimports int) { +func testDir(t *testing.T, dir string, endTime time.Time) (nimports int) { dirname := filepath.Join(pkgRoot, dir) list, err := ioutil.ReadDir(dirname) if err != nil { t.Errorf("testDir(%s): %s", dirname, err) } for _, f := range list { - if time.Nanoseconds() >= endTime { + if time.Now().After(endTime) { t.Log("testing time used up") return } switch { - case f.IsRegular(): + case !f.IsDir(): // try extensions for _, ext := range pkgExts { - if strings.HasSuffix(f.Name, ext) { - name := f.Name[0 : len(f.Name)-len(ext)] // remove extension + if strings.HasSuffix(f.Name(), ext) { + name := f.Name()[0 : len(f.Name())-len(ext)] // remove extension if testPath(t, filepath.Join(dir, name)) { nimports++ } } } - case f.IsDirectory(): - nimports += testDir(t, filepath.Join(dir, f.Name), endTime) + case f.IsDir(): + nimports += testDir(t, filepath.Join(dir, f.Name()), endTime) } } return @@ -96,6 +96,6 @@ func TestGcImport(t *testing.T) { if testPath(t, "./testdata/exports") { nimports++ } - nimports += testDir(t, "", time.Nanoseconds()+maxTime) // installed packages + nimports += testDir(t, "", time.Now().Add(maxTime)) // installed packages t.Logf("tested %d imports", nimports) } diff --git a/libgo/go/fmt/fmt_test.go b/libgo/go/fmt/fmt_test.go index 6370560d0bf..00aac798cb0 100644 --- a/libgo/go/fmt/fmt_test.go +++ b/libgo/go/fmt/fmt_test.go @@ -47,8 +47,10 @@ func TestFmtInterface(t *testing.T) { const b32 uint32 = 1<<32 - 1 const b64 uint64 = 1<<64 - 1 -var array = []int{1, 2, 3, 4, 5} -var iarray = []interface{}{1, "hello", 2.5, nil} +var array = [5]int{1, 2, 3, 4, 5} +var iarray = [4]interface{}{1, "hello", 2.5, nil} +var slice = array[:] +var islice = iarray[:] type A struct { i int @@ -327,6 +329,12 @@ var fmttests = []struct { {"%v", &array, "&[1 2 3 4 5]"}, {"%v", &iarray, "&[1 hello 2.5 ]"}, + // slices + {"%v", slice, "[1 2 3 4 5]"}, + {"%v", islice, "[1 hello 2.5 ]"}, + {"%v", &slice, "&[1 2 3 4 5]"}, + {"%v", &islice, "&[1 hello 2.5 ]"}, + // complexes with %v {"%v", 1 + 2i, "(1+2i)"}, {"%v", complex64(1 + 2i), "(1+2i)"}, @@ -359,6 +367,10 @@ var fmttests = []struct { {"%#v", SI{}, `fmt_test.SI{I:interface {}(nil)}`}, {"%#v", []int(nil), `[]int(nil)`}, {"%#v", []int{}, `[]int{}`}, + {"%#v", array, `[5]int{1, 2, 3, 4, 5}`}, + {"%#v", &array, `&[5]int{1, 2, 3, 4, 5}`}, + {"%#v", iarray, `[4]interface {}{1, "hello", 2.5, interface {}(nil)}`}, + {"%#v", &iarray, `&[4]interface {}{1, "hello", 2.5, interface {}(nil)}`}, {"%#v", map[int]byte(nil), `map[int] uint8(nil)`}, {"%#v", map[int]byte{}, `map[int] uint8{}`}, diff --git a/libgo/go/fmt/print.go b/libgo/go/fmt/print.go index 7143e07a36e..e5ca1172405 100644 --- a/libgo/go/fmt/print.go +++ b/libgo/go/fmt/print.go @@ -877,7 +877,7 @@ BigSwitch: } if goSyntax { p.buf.WriteString(value.Type().String()) - if f.IsNil() { + if f.Kind() == reflect.Slice && f.IsNil() { p.buf.WriteString("(nil)") break } diff --git a/libgo/go/go/ast/resolve.go b/libgo/go/go/ast/resolve.go index b24688d2ea3..c7c8e7c101e 100644 --- a/libgo/go/go/ast/resolve.go +++ b/libgo/go/go/ast/resolve.go @@ -113,7 +113,7 @@ func NewPackage(fset *token.FileSet, files map[string]*File, importer Importer, importErrors = true continue } - path, _ := strconv.Unquote(string(spec.Path.Value)) + path, _ := strconv.Unquote(spec.Path.Value) pkg, err := importer(imports, path) if err != nil { p.errorf(spec.Path.Pos(), "could not import %s (%s)", path, err) diff --git a/libgo/go/go/build/build.go b/libgo/go/go/build/build.go index e3de8d0fa7f..5301ab53e51 100644 --- a/libgo/go/go/build/build.go +++ b/libgo/go/go/build/build.go @@ -15,6 +15,7 @@ import ( "regexp" "runtime" "strings" + "time" ) // Build produces a build Script for the given package. @@ -150,7 +151,7 @@ func (s *Script) Run() error { // Stale returns true if the build's inputs are newer than its outputs. func (s *Script) Stale() bool { - var latest int64 + var latest time.Time // get latest mtime of outputs for _, file := range s.Output { fi, err := os.Stat(file) @@ -158,13 +159,13 @@ func (s *Script) Stale() bool { // any error reading output files means stale return true } - if m := fi.Mtime_ns; m > latest { - latest = m + if mtime := fi.ModTime(); mtime.After(latest) { + latest = mtime } } for _, file := range s.Input { fi, err := os.Stat(file) - if err != nil || fi.Mtime_ns > latest { + if err != nil || fi.ModTime().After(latest) { // any error reading input files means stale // (attempt to rebuild to figure out why) return true diff --git a/libgo/go/go/build/dir.go b/libgo/go/go/build/dir.go index 0d175c75deb..12dc99942a7 100644 --- a/libgo/go/go/build/dir.go +++ b/libgo/go/go/build/dir.go @@ -38,16 +38,16 @@ type Context struct { // format of the strings dir and file: they can be // slash-separated, backslash-separated, even URLs. - // ReadDir returns a slice of *os.FileInfo, sorted by Name, + // ReadDir returns a slice of os.FileInfo, sorted by Name, // describing the content of the named directory. // The dir argument is the argument to ScanDir. // If ReadDir is nil, ScanDir uses io.ReadDir. - ReadDir func(dir string) (fi []*os.FileInfo, err error) + ReadDir func(dir string) (fi []os.FileInfo, err error) // ReadFile returns the content of the file named file // in the directory named dir. The dir argument is the // argument to ScanDir, and the file argument is the - // Name field from an *os.FileInfo returned by ReadDir. + // Name field from an os.FileInfo returned by ReadDir. // The returned path is the full name of the file, to be // used in error messages. // @@ -56,7 +56,7 @@ type Context struct { ReadFile func(dir, file string) (path string, content []byte, err error) } -func (ctxt *Context) readDir(dir string) ([]*os.FileInfo, error) { +func (ctxt *Context) readDir(dir string) ([]os.FileInfo, error) { if f := ctxt.ReadDir; f != nil { return f(dir) } @@ -140,18 +140,19 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) { testImported := make(map[string]bool) fset := token.NewFileSet() for _, d := range dirs { - if !d.IsRegular() { + if d.IsDir() { continue } - if strings.HasPrefix(d.Name, "_") || - strings.HasPrefix(d.Name, ".") { + name := d.Name() + if strings.HasPrefix(name, "_") || + strings.HasPrefix(name, ".") { continue } - if !ctxt.goodOSArchFile(d.Name) { + if !ctxt.goodOSArchFile(name) { continue } - ext := path.Ext(d.Name) + ext := path.Ext(name) switch ext { case ".go", ".c", ".s": // tentatively okay @@ -161,7 +162,7 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) { } // Look for +build comments to accept or reject the file. - filename, data, err := ctxt.readFile(dir, d.Name) + filename, data, err := ctxt.readFile(dir, name) if err != nil { return nil, err } @@ -172,10 +173,10 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) { // Going to save the file. For non-Go files, can stop here. switch ext { case ".c": - di.CFiles = append(di.CFiles, d.Name) + di.CFiles = append(di.CFiles, name) continue case ".s": - di.SFiles = append(di.SFiles, d.Name) + di.SFiles = append(di.SFiles, name) continue } @@ -192,7 +193,7 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) { continue } - isTest := strings.HasSuffix(d.Name, "_test.go") + isTest := strings.HasSuffix(name, "_test.go") if isTest && strings.HasSuffix(pkg, "_test") { pkg = pkg[:len(pkg)-len("_test")] } @@ -255,15 +256,15 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) { } } if isCgo { - di.CgoFiles = append(di.CgoFiles, d.Name) + di.CgoFiles = append(di.CgoFiles, name) } else if isTest { if pkg == string(pf.Name.Name) { - di.TestGoFiles = append(di.TestGoFiles, d.Name) + di.TestGoFiles = append(di.TestGoFiles, name) } else { - di.XTestGoFiles = append(di.XTestGoFiles, d.Name) + di.XTestGoFiles = append(di.XTestGoFiles, name) } } else { - di.GoFiles = append(di.GoFiles, d.Name) + di.GoFiles = append(di.GoFiles, name) } } if di.Package == "" { diff --git a/libgo/go/go/build/path.go b/libgo/go/go/build/path.go index 7ccb12993b3..91d6c430a9d 100644 --- a/libgo/go/go/build/path.go +++ b/libgo/go/go/build/path.go @@ -70,7 +70,7 @@ func (t *Tree) HasSrc(pkg string) bool { if err != nil { return false } - return fi.IsDirectory() + return fi.IsDir() } // HasPkg returns whether the given package's @@ -80,7 +80,7 @@ func (t *Tree) HasPkg(pkg string) bool { if err != nil { return false } - return fi.IsRegular() + return !fi.IsDir() // TODO(adg): check object version is consistent } diff --git a/libgo/go/go/doc/comment.go b/libgo/go/go/doc/comment.go index 19216f85b96..d7bb384ed03 100644 --- a/libgo/go/go/doc/comment.go +++ b/libgo/go/go/doc/comment.go @@ -7,11 +7,14 @@ package doc import ( + "bytes" "go/ast" "io" "regexp" "strings" "text/template" // for HTMLEscape + "unicode" + "unicode/utf8" ) func isWhitespace(ch byte) bool { return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' } @@ -168,6 +171,8 @@ var ( html_endp = []byte("

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

") + html_endh = []byte("

\n") ) // Emphasize and escape a line of text for HTML. URLs are converted into links; @@ -268,6 +273,51 @@ func unindent(block [][]byte) { } } +// heading returns the (possibly trimmed) line if it passes as a valid section +// heading; otherwise it returns nil. +func heading(line []byte) []byte { + line = bytes.TrimSpace(line) + if len(line) == 0 { + return nil + } + + // a heading must start with an uppercase letter + r, _ := utf8.DecodeRune(line) + if !unicode.IsLetter(r) || !unicode.IsUpper(r) { + return nil + } + + // it must end in a letter, digit or ':' + r, _ = utf8.DecodeLastRune(line) + if !unicode.IsLetter(r) && !unicode.IsDigit(r) && r != ':' { + return nil + } + + // strip trailing ':', if any + if r == ':' { + line = line[0 : len(line)-1] + } + + // exclude lines with illegal characters + if bytes.IndexAny(line, ",.;:!?+*/=()[]{}_^°&§~%#@<\">\\") >= 0 { + return nil + } + + // allow "'" for possessive "'s" only + for b := line; ; { + i := bytes.IndexRune(b, '\'') + if i < 0 { + break + } + if i+1 >= len(b) || b[i+1] != 's' || (i+2 < len(b) && b[i+2] != ' ') { + return nil // not followed by "s " + } + b = b[i+2:] + } + + return line +} + // Convert comment text to formatted HTML. // The comment was prepared by DocReader, // so it is known not to have leading, trailing blank lines @@ -276,6 +326,7 @@ func unindent(block [][]byte) { // // Turn each run of multiple \n into

. // Turn each run of indented lines into a

 block without indent.
+// Enclose headings with header tags.
 //
 // URLs in the comment text are converted into links; if the URL also appears
 // in the words map, the link is taken from the map (if the corresponding map
@@ -286,6 +337,8 @@ func unindent(block [][]byte) {
 // into a link.
 func ToHTML(w io.Writer, s []byte, words map[string]string) {
 	inpara := false
+	lastWasBlank := false
+	lastWasHeading := false
 
 	close := func() {
 		if inpara {
@@ -308,6 +361,7 @@ func ToHTML(w io.Writer, s []byte, words map[string]string) {
 			// close paragraph
 			close()
 			i++
+			lastWasBlank = true
 			continue
 		}
 		if indentLen(line) > 0 {
@@ -334,10 +388,30 @@ func ToHTML(w io.Writer, s []byte, words map[string]string) {
 				emphasize(w, line, nil, false) // no nice text formatting
 			}
 			w.Write(html_endpre)
+			lastWasHeading = false
 			continue
 		}
+
+		if lastWasBlank && !lastWasHeading && i+2 < len(lines) &&
+			isBlank(lines[i+1]) && !isBlank(lines[i+2]) && indentLen(lines[i+2]) == 0 {
+			// current line is non-blank, sourounded by blank lines
+			// and the next non-blank line is not indented: this
+			// might be a heading.
+			if head := heading(line); head != nil {
+				close()
+				w.Write(html_h)
+				template.HTMLEscape(w, head)
+				w.Write(html_endh)
+				i += 2
+				lastWasHeading = true
+				continue
+			}
+		}
+
 		// open paragraph
 		open()
+		lastWasBlank = false
+		lastWasHeading = false
 		emphasize(w, lines[i], words, true) // nice text formatting
 		i++
 	}
diff --git a/libgo/go/go/doc/comment_test.go b/libgo/go/go/doc/comment_test.go
new file mode 100644
index 00000000000..870660ad628
--- /dev/null
+++ b/libgo/go/go/doc/comment_test.go
@@ -0,0 +1,39 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package doc
+
+import (
+	"testing"
+)
+
+var headingTests = []struct {
+	line string
+	ok   bool
+}{
+	{"Section", true},
+	{"A typical usage", true},
+	{"ΔΛΞ is Greek", true},
+	{"Foo 42", true},
+	{"", false},
+	{"section", false},
+	{"A typical usage:", true},
+	{"δ is Greek", false},
+	{"Foo §", false},
+	{"Fermat's Last Sentence", true},
+	{"Fermat's", true},
+	{"'sX", false},
+	{"Ted 'Too' Bar", false},
+	{"Use n+m", false},
+	{"Scanning:", true},
+	{"N:M", false},
+}
+
+func TestIsHeading(t *testing.T) {
+	for _, tt := range headingTests {
+		if h := heading([]byte(tt.line)); (h != nil) != tt.ok {
+			t.Errorf("isHeading(%q) = %v, want %v", tt.line, h, tt.ok)
+		}
+	}
+}
diff --git a/libgo/go/go/doc/headscan.go b/libgo/go/go/doc/headscan.go
new file mode 100644
index 00000000000..83f24627c95
--- /dev/null
+++ b/libgo/go/go/doc/headscan.go
@@ -0,0 +1,111 @@
+// 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.
+
+/*
+	The headscan command extracts comment headings from package files;
+	it is used to detect false positives which may require an adjustment
+	to the comment formatting heuristics in comment.go.
+
+	Usage: headscan [-root root_directory]
+
+	By default, the $GOROOT/src directory is scanned.
+*/
+package main
+
+import (
+	"bytes"
+	"flag"
+	"fmt"
+	"go/doc"
+	"go/parser"
+	"go/token"
+	"os"
+	"path/filepath"
+	"runtime"
+	"strings"
+)
+
+var (
+	root    = flag.String("root", filepath.Join(runtime.GOROOT(), "src"), "root of filesystem tree to scan")
+	verbose = flag.Bool("v", false, "verbose mode")
+)
+
+const (
+	html_h    = "

" + html_endh = "

\n" +) + +func isGoFile(fi os.FileInfo) bool { + return strings.HasSuffix(fi.Name(), ".go") && + !strings.HasSuffix(fi.Name(), "_test.go") +} + +func appendHeadings(list []string, comment string) []string { + var buf bytes.Buffer + doc.ToHTML(&buf, []byte(comment), nil) + for s := buf.String(); ; { + i := strings.Index(s, html_h) + if i < 0 { + break + } + i += len(html_h) + j := strings.Index(s, html_endh) + if j < 0 { + list = append(list, s[i:]) // incorrect HTML + break + } + list = append(list, s[i:j]) + s = s[j+len(html_endh):] + } + return list +} + +func main() { + flag.Parse() + fset := token.NewFileSet() + nheadings := 0 + err := filepath.Walk(*root, func(path string, fi os.FileInfo, err error) error { + if !fi.IsDir() { + return nil + } + pkgs, err := parser.ParseDir(fset, path, isGoFile, parser.ParseComments) + if err != nil { + if *verbose { + fmt.Fprintln(os.Stderr, err) + } + return nil + } + for _, pkg := range pkgs { + d := doc.NewPackageDoc(pkg, path) + list := appendHeadings(nil, d.Doc) + for _, d := range d.Consts { + list = appendHeadings(list, d.Doc) + } + for _, d := range d.Types { + list = appendHeadings(list, d.Doc) + } + for _, d := range d.Vars { + list = appendHeadings(list, d.Doc) + } + for _, d := range d.Funcs { + list = appendHeadings(list, d.Doc) + } + if len(list) > 0 { + // directories may contain multiple packages; + // print path and package name + fmt.Printf("%s (package %s)\n", path, pkg.Name) + for _, h := range list { + fmt.Printf("\t%s\n", h) + } + nheadings += len(list) + } + } + return nil + }) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + fmt.Println(nheadings, "headings found") +} diff --git a/libgo/go/go/parser/interface.go b/libgo/go/go/parser/interface.go index d3bab31c5a3..be11f461c3b 100644 --- a/libgo/go/go/parser/interface.go +++ b/libgo/go/go/parser/interface.go @@ -188,7 +188,7 @@ func ParseFiles(fset *token.FileSet, filenames []string, mode uint) (pkgs map[st // returned. If a parse error occurred, a non-nil but incomplete map and the // error are returned. // -func ParseDir(fset *token.FileSet, path string, filter func(*os.FileInfo) bool, mode uint) (map[string]*ast.Package, error) { +func ParseDir(fset *token.FileSet, path string, filter func(os.FileInfo) bool, mode uint) (map[string]*ast.Package, error) { fd, err := os.Open(path) if err != nil { return nil, err @@ -202,10 +202,9 @@ func ParseDir(fset *token.FileSet, path string, filter func(*os.FileInfo) bool, filenames := make([]string, len(list)) n := 0 - for i := 0; i < len(list); i++ { - d := &list[i] + for _, d := range list { if filter == nil || filter(d) { - filenames[n] = filepath.Join(path, d.Name) + filenames[n] = filepath.Join(path, d.Name()) n++ } } diff --git a/libgo/go/go/parser/parser_test.go b/libgo/go/go/parser/parser_test.go index dee90fbcf4c..f602db8896d 100644 --- a/libgo/go/go/parser/parser_test.go +++ b/libgo/go/go/parser/parser_test.go @@ -113,7 +113,7 @@ func nameFilter(filename string) bool { return true } -func dirFilter(f *os.FileInfo) bool { return nameFilter(f.Name) } +func dirFilter(f os.FileInfo) bool { return nameFilter(f.Name()) } func TestParse4(t *testing.T) { path := "." diff --git a/libgo/go/go/printer/nodes.go b/libgo/go/go/printer/nodes.go index 248e43d4e72..53f36092fda 100644 --- a/libgo/go/go/printer/nodes.go +++ b/libgo/go/go/printer/nodes.go @@ -1377,7 +1377,7 @@ func (p *printer) nodeSize(n ast.Node, maxSize int) (size int) { // in RawFormat cfg := Config{Mode: RawFormat} var buf bytes.Buffer - if _, err := cfg.fprint(&buf, p.fset, n, p.nodeSizes); err != nil { + if err := cfg.fprint(&buf, p.fset, n, p.nodeSizes); err != nil { return } if buf.Len() <= maxSize { diff --git a/libgo/go/go/printer/performance_test.go b/libgo/go/go/printer/performance_test.go index 84fb2808eba..dbd942292b5 100644 --- a/libgo/go/go/printer/performance_test.go +++ b/libgo/go/go/printer/performance_test.go @@ -20,7 +20,7 @@ import ( var testfile *ast.File func testprint(out io.Writer, file *ast.File) { - if _, err := (&Config{TabIndent | UseSpaces, 8}).Fprint(out, fset, file); err != nil { + if err := (&Config{TabIndent | UseSpaces, 8}).Fprint(out, fset, file); err != nil { log.Fatalf("print error: %s", err) } } diff --git a/libgo/go/go/printer/printer.go b/libgo/go/go/printer/printer.go index 6104c326c66..f8c22f1419d 100644 --- a/libgo/go/go/printer/printer.go +++ b/libgo/go/go/printer/printer.go @@ -19,9 +19,9 @@ import ( ) const debug = false // enable for debugging +const infinity = 1 << 30 - -type whiteSpace int +type whiteSpace byte const ( ignore = whiteSpace(0) @@ -33,18 +33,6 @@ const ( unindent = whiteSpace('<') ) -var ( - esc = []byte{tabwriter.Escape} - htab = []byte{'\t'} - htabs = []byte("\t\t\t\t\t\t\t\t") - newlines = []byte("\n\n\n\n\n\n\n\n") // more than the max determined by nlines - formfeeds = []byte("\f\f\f\f\f\f\f\f") // more than the max determined by nlines -) - -// Special positions -var noPos token.Position // use noPos when a position is needed but not known -var infinity = 1 << 30 - // Use ignoreMultiLine if the multiLine information is not important. var ignoreMultiLine = new(bool) @@ -52,31 +40,20 @@ var ignoreMultiLine = new(bool) type pmode int const ( - inLiteral pmode = 1 << iota - noExtraLinebreak + noExtraLinebreak pmode = 1 << iota ) -// local error wrapper so we can distinguish errors we want to return -// as errors from genuine panics (which we don't want to return as errors) -type osError struct { - err error -} - type printer struct { // Configuration (does not change after initialization) - output io.Writer Config fset *token.FileSet // Current state - written int // number of bytes written - indent int // current indentation - mode pmode // current printer mode - lastTok token.Token // the last token printed (token.ILLEGAL if it's whitespace) - - // Reused buffers - wsbuf []whiteSpace // delayed white space - litbuf bytes.Buffer // for creation of escaped literals and comments + output bytes.Buffer // raw printer result + indent int // current indentation + mode pmode // current printer mode + lastTok token.Token // the last token printed (token.ILLEGAL if it's whitespace) + wsbuf []whiteSpace // delayed white space // The (possibly estimated) position in the generated output; // in AST space (i.e., pos is set whenever a token position is @@ -97,8 +74,7 @@ type printer struct { nodeSizes map[ast.Node]int } -func (p *printer) init(output io.Writer, cfg *Config, fset *token.FileSet, nodeSizes map[ast.Node]int) { - p.output = output +func (p *printer) init(cfg *Config, fset *token.FileSet, nodeSizes map[ast.Node]int) { p.Config = *cfg p.fset = fset p.wsbuf = make([]whiteSpace, 0, 16) // whitespace sequences are short @@ -113,19 +89,6 @@ func (p *printer) internalError(msg ...interface{}) { } } -// escape escapes string s by bracketing it with tabwriter.Escape. -// Escaped strings pass through tabwriter unchanged. (Note that -// valid Go programs cannot contain tabwriter.Escape bytes since -// they do not appear in legal UTF-8 sequences). -// -func (p *printer) escape(s string) string { - p.litbuf.Reset() - p.litbuf.WriteByte(tabwriter.Escape) - p.litbuf.WriteString(s) - p.litbuf.WriteByte(tabwriter.Escape) - return p.litbuf.String() -} - // nlines returns the adjusted number of linebreaks given the desired number // of breaks n such that min <= result <= max. // @@ -140,82 +103,79 @@ func (p *printer) nlines(n, min int) int { return n } -// write0 writes raw (uninterpreted) data to p.output and handles errors. -// write0 does not indent after newlines, and does not HTML-escape or update p.pos. -// -func (p *printer) write0(data []byte) { - if len(data) > 0 { - n, err := p.output.Write(data) - p.written += n - if err != nil { - panic(osError{err}) +// writeByte writes a single byte to p.output and updates p.pos. +func (p *printer) writeByte(ch byte) { + p.output.WriteByte(ch) + p.pos.Offset++ + p.pos.Column++ + + if ch == '\n' || ch == '\f' { + // write indentation + // use "hard" htabs - indentation columns + // must not be discarded by the tabwriter + const htabs = "\t\t\t\t\t\t\t\t" + j := p.indent + for j > len(htabs) { + p.output.WriteString(htabs) + j -= len(htabs) } + p.output.WriteString(htabs[0:j]) + + // update p.pos + p.pos.Line++ + p.pos.Offset += p.indent + p.pos.Column = 1 + p.indent } } -// write interprets data and writes it to p.output. It inserts indentation -// after a line break unless in a tabwriter escape sequence. -// It updates p.pos as a side-effect. +// writeNewlines writes up to n newlines to p.output and updates p.pos. +// The actual number of newlines written is limited by nlines. +// nl must be one of '\n' or '\f'. // -func (p *printer) write(data []byte) { - i0 := 0 - for i, b := range data { - switch b { - case '\n', '\f': - // write segment ending in b - p.write0(data[i0 : i+1]) +func (p *printer) writeNewlines(n int, nl byte) { + for n = p.nlines(n, 0); n > 0; n-- { + p.writeByte(nl) + } +} - // update p.pos - p.pos.Offset += i + 1 - i0 - p.pos.Line++ - p.pos.Column = 1 - - if p.mode&inLiteral == 0 { - // write indentation - // use "hard" htabs - indentation columns - // must not be discarded by the tabwriter - j := p.indent - for ; j > len(htabs); j -= len(htabs) { - p.write0(htabs) - } - p.write0(htabs[0:j]) - - // update p.pos - p.pos.Offset += p.indent - p.pos.Column += p.indent - } - - // next segment start - i0 = i + 1 - - case tabwriter.Escape: - p.mode ^= inLiteral - - // ignore escape chars introduced by printer - they are - // invisible and must not affect p.pos (was issue #1089) - p.pos.Offset-- - p.pos.Column-- - } +// writeString writes the string s to p.output and updates p.pos. +// If isLit is set, s is escaped w/ tabwriter.Escape characters +// to protect s from being interpreted by the tabwriter. +// +// Note: writeString is only used to write Go tokens, literals, and +// comments, all of which must be written literally. Thus, it is correct +// to always set isLit = true. However, setting it explicitly only when +// needed (i.e., when we don't know that s contains no tabs or line breaks) +// avoids processing extra escape characters and reduces run time of the +// printer benchmark by up to 10%. +// +func (p *printer) writeString(s string, isLit bool) { + if isLit { + // Protect s such that is passes through the tabwriter + // unchanged. Note that valid Go programs cannot contain + // tabwriter.Escape bytes since they do not appear in legal + // UTF-8 sequences. + p.output.WriteByte(tabwriter.Escape) } - // write remaining segment - p.write0(data[i0:]) + p.output.WriteString(s) // update p.pos - d := len(data) - i0 - p.pos.Offset += d - p.pos.Column += d -} - -func (p *printer) writeNewlines(n int, useFF bool) { - if n > 0 { - n = p.nlines(n, 0) - if useFF { - p.write(formfeeds[0:n]) - } else { - p.write(newlines[0:n]) + nlines := 0 + column := p.pos.Column + len(s) + for i := 0; i < len(s); i++ { + if s[i] == '\n' { + nlines++ + column = len(s) - i } } + p.pos.Offset += len(s) + p.pos.Line += nlines + p.pos.Column = column + + if isLit { + p.output.WriteByte(tabwriter.Escape) + } } // writeItem writes data at position pos. data is the text corresponding to @@ -224,7 +184,7 @@ func (p *printer) writeNewlines(n int, useFF bool) { // source text. writeItem updates p.last to the position immediately following // the data. // -func (p *printer) writeItem(pos token.Position, data string) { +func (p *printer) writeItem(pos token.Position, data string, isLit bool) { if pos.IsValid() { // continue with previous position if we don't have a valid pos if p.last.IsValid() && p.last.Filename != pos.Filename { @@ -240,9 +200,9 @@ func (p *printer) writeItem(pos token.Position, data string) { if debug { // do not update p.pos - use write0 _, filename := filepath.Split(pos.Filename) - p.write0([]byte(fmt.Sprintf("[%s:%d:%d]", filename, pos.Line, pos.Column))) + fmt.Fprintf(&p.output, "[%s:%d:%d]", filename, pos.Line, pos.Column) } - p.write([]byte(data)) + p.writeString(data, isLit) p.last = p.pos } @@ -257,14 +217,14 @@ const linePrefix = "//line " // next item is a keyword. // func (p *printer) writeCommentPrefix(pos, next token.Position, prev, comment *ast.Comment, isKeyword bool) { - if p.written == 0 { + if p.output.Len() == 0 { // the comment is the first item to be printed - don't write any whitespace return } if pos.IsValid() && pos.Filename != p.last.Filename { // comment in a different file - separate with newlines (writeNewlines will limit the number) - p.writeNewlines(10, true) + p.writeNewlines(10, '\f') return } @@ -297,14 +257,14 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, prev, comment *as } // make sure there is at least one separator if !hasSep { + sep := byte('\t') if pos.Line == next.Line { // next item is on the same line as the comment // (which must be a /*-style comment): separate // with a blank instead of a tab - p.write([]byte{' '}) - } else { - p.write(htab) + sep = ' ' } + p.writeByte(sep) } } else { @@ -357,30 +317,31 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, prev, comment *as if n <= 0 && prev != nil && prev.Text[1] == '/' { n = 1 } - p.writeNewlines(n, true) + if n > 0 { + p.writeNewlines(n, '\f') + } p.indent = indent } } -// TODO(gri): It should be possible to convert the code below from using -// []byte to string and in the process eliminate some conversions. - // Split comment text into lines -func split(text []byte) [][]byte { +// (using strings.Split(text, "\n") is significantly slower for +// this specific purpose, as measured with: gotest -bench=Print) +func split(text string) []string { // count lines (comment text never ends in a newline) n := 1 - for _, c := range text { - if c == '\n' { + for i := 0; i < len(text); i++ { + if text[i] == '\n' { n++ } } // split - lines := make([][]byte, n) + lines := make([]string, n) n = 0 i := 0 - for j, c := range text { - if c == '\n' { + for j := 0; j < len(text); j++ { + if text[j] == '\n' { lines[n] = text[i:j] // exclude newline i = j + 1 // discard newline n++ @@ -391,16 +352,18 @@ func split(text []byte) [][]byte { return lines } -func isBlank(s []byte) bool { - for _, b := range s { - if b > ' ' { +// Returns true if s contains only white space +// (only tabs and blanks can appear in the printer's context). +func isBlank(s string) bool { + for i := 0; i < len(s); i++ { + if s[i] > ' ' { return false } } return true } -func commonPrefix(a, b []byte) []byte { +func commonPrefix(a, b string) string { i := 0 for i < len(a) && i < len(b) && a[i] == b[i] && (a[i] <= ' ' || a[i] == '*') { i++ @@ -408,7 +371,7 @@ func commonPrefix(a, b []byte) []byte { return a[0:i] } -func stripCommonPrefix(lines [][]byte) { +func stripCommonPrefix(lines []string) { if len(lines) < 2 { return // at most one line - nothing to do } @@ -432,19 +395,21 @@ func stripCommonPrefix(lines [][]byte) { // Note that the first and last line are never empty (they // contain the opening /* and closing */ respectively) and // thus they can be ignored by the blank line check. - var prefix []byte + var prefix string if len(lines) > 2 { + first := true for i, line := range lines[1 : len(lines)-1] { switch { case isBlank(line): - lines[1+i] = nil // range starts at line 1 - case prefix == nil: + lines[1+i] = "" // range starts at line 1 + case first: prefix = commonPrefix(line, line) + first = false default: prefix = commonPrefix(prefix, line) } } - } else { // len(lines) == 2 + } else { // len(lines) == 2, lines cannot be blank (contain /* and */) line := lines[1] prefix = commonPrefix(line, line) } @@ -453,7 +418,7 @@ func stripCommonPrefix(lines [][]byte) { * Check for vertical "line of stars" and correct prefix accordingly. */ lineOfStars := false - if i := bytes.Index(prefix, []byte{'*'}); i >= 0 { + if i := strings.Index(prefix, "*"); i >= 0 { // Line of stars present. if i > 0 && prefix[i-1] == ' ' { i-- // remove trailing blank from prefix so stars remain aligned @@ -501,7 +466,7 @@ func stripCommonPrefix(lines [][]byte) { } // Shorten the computed common prefix by the length of // suffix, if it is found as suffix of the prefix. - if bytes.HasSuffix(prefix, suffix) { + if strings.HasSuffix(prefix, string(suffix)) { prefix = prefix[0 : len(prefix)-len(suffix)] } } @@ -511,19 +476,18 @@ func stripCommonPrefix(lines [][]byte) { // with the opening /*, otherwise align the text with the other // lines. last := lines[len(lines)-1] - closing := []byte("*/") - i := bytes.Index(last, closing) + closing := "*/" + i := strings.Index(last, closing) // i >= 0 (closing is always present) if isBlank(last[0:i]) { // last line only contains closing */ - var sep []byte if lineOfStars { - // insert an aligning blank - sep = []byte{' '} + closing = " */" // add blank to align final star } - lines[len(lines)-1] = bytes.Join([][]byte{prefix, closing}, sep) + lines[len(lines)-1] = prefix + closing } else { // last line contains more comment text - assume - // it is aligned like the other lines + // it is aligned like the other lines and include + // in prefix computation prefix = commonPrefix(prefix, last) } @@ -549,9 +513,9 @@ func (p *printer) writeComment(comment *ast.Comment) { // update our own idea of the file and line number // accordingly, after printing the directive. file := pos[:i] - line, _ := strconv.Atoi(string(pos[i+1:])) + line, _ := strconv.Atoi(pos[i+1:]) defer func() { - p.pos.Filename = string(file) + p.pos.Filename = file p.pos.Line = line p.pos.Column = 1 }() @@ -560,26 +524,25 @@ func (p *printer) writeComment(comment *ast.Comment) { // shortcut common case of //-style comments if text[1] == '/' { - p.writeItem(p.fset.Position(comment.Pos()), p.escape(text)) + p.writeItem(p.fset.Position(comment.Pos()), text, true) return } // for /*-style comments, print line by line and let the // write function take care of the proper indentation - lines := split([]byte(text)) + lines := split(text) stripCommonPrefix(lines) // write comment lines, separated by formfeed, // without a line break after the last line - linebreak := formfeeds[0:1] pos := p.fset.Position(comment.Pos()) for i, line := range lines { if i > 0 { - p.write(linebreak) + p.writeByte('\f') pos = p.pos } if len(line) > 0 { - p.writeItem(pos, p.escape(string(line))) + p.writeItem(pos, line, true) } } } @@ -615,7 +578,7 @@ func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) { // make sure we have a line break if needsLinebreak { - p.write([]byte{'\n'}) + p.writeByte('\n') } return @@ -641,7 +604,7 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (dro if last.Text[1] == '*' && p.fset.Position(last.Pos()).Line == next.Line { // the last comment is a /*-style comment and the next item // follows on the same line: separate with an extra blank - p.write([]byte{' '}) + p.writeByte(' ') } // ensure that there is a line break after a //-style comment, // before a closing '}' unless explicitly disabled, or at eof @@ -661,7 +624,6 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (dro // whiteWhitespace writes the first n whitespace entries. func (p *printer) writeWhitespace(n int) { // write entries - var data [1]byte for i := 0; i < n; i++ { switch ch := p.wsbuf[i]; ch { case ignore: @@ -693,8 +655,7 @@ func (p *printer) writeWhitespace(n int) { } fallthrough default: - data[0] = byte(ch) - p.write(data[0:]) + p.writeByte(byte(ch)) } } @@ -710,7 +671,6 @@ func (p *printer) writeWhitespace(n int) { // ---------------------------------------------------------------------------- // Printing interface - func mayCombine(prev token.Token, next byte) (b bool) { switch prev { case token.INT: @@ -743,7 +703,8 @@ func mayCombine(prev token.Token, next byte) (b bool) { func (p *printer) print(args ...interface{}) { for _, f := range args { next := p.pos // estimated position of next item - var data string + data := "" + isLit := false var tok token.Token switch x := f.(type) { @@ -771,7 +732,8 @@ func (p *printer) print(args ...interface{}) { data = x.Name tok = token.IDENT case *ast.BasicLit: - data = p.escape(x.Value) + data = x.Value + isLit = true tok = x.Kind case token.Token: s := x.String() @@ -803,15 +765,20 @@ func (p *printer) print(args ...interface{}) { p.pos = next if data != "" { - droppedFF := p.flush(next, tok) + nl := byte('\n') + if p.flush(next, tok) { + nl = '\f' // dropped formfeed before + } // intersperse extra newlines if present in the source // (don't do this in flush as it will cause extra newlines // at the end of a file) - use formfeeds if we dropped one // before - p.writeNewlines(next.Line-p.pos.Line, droppedFF) + if n := next.Line - p.pos.Line; n > 0 { + p.writeNewlines(n, nl) + } - p.writeItem(next, data) + p.writeItem(next, data, isLit) } } } @@ -840,6 +807,35 @@ func (p *printer) flush(next token.Position, tok token.Token) (droppedFF bool) { return } +func (p *printer) printNode(node interface{}) error { + switch n := node.(type) { + case ast.Expr: + p.useNodeComments = true + p.expr(n, ignoreMultiLine) + case ast.Stmt: + p.useNodeComments = true + // A labeled statement will un-indent to position the + // label. Set indent to 1 so we don't get indent "underflow". + if _, labeledStmt := n.(*ast.LabeledStmt); labeledStmt { + p.indent = 1 + } + p.stmt(n, false, ignoreMultiLine) + case ast.Decl: + p.useNodeComments = true + p.decl(n, ignoreMultiLine) + case ast.Spec: + p.useNodeComments = true + p.spec(n, 1, false, ignoreMultiLine) + case *ast.File: + p.comments = n.Comments + p.useNodeComments = n.Comments == nil + p.file(n) + default: + return fmt.Errorf("go/printer: unsupported node type %T", n) + } + return nil +} + // ---------------------------------------------------------------------------- // Trimmer @@ -869,6 +865,8 @@ const ( // However, this would mess up any formatting done by // the tabwriter. +var aNewline = []byte("\n") + func (p *trimmer) Write(data []byte) (n int, err error) { // invariants: // p.state == inSpace: @@ -887,8 +885,8 @@ func (p *trimmer) Write(data []byte) (n int, err error) { case '\t', ' ': p.space.WriteByte(b) // WriteByte returns no errors case '\n', '\f': - p.space.Reset() // discard trailing space - _, err = p.output.Write(newlines[0:1]) // write newline + p.space.Reset() // discard trailing space + _, err = p.output.Write(aNewline) case tabwriter.Escape: _, err = p.output.Write(p.space.Bytes()) p.state = inEscape @@ -915,7 +913,7 @@ func (p *trimmer) Write(data []byte) (n int, err error) { _, err = p.output.Write(data[m:n]) p.state = inSpace p.space.Reset() - _, err = p.output.Write(newlines[0:1]) // write newline + _, err = p.output.Write(aNewline) case tabwriter.Escape: _, err = p.output.Write(data[m:n]) p.state = inEscape @@ -957,15 +955,22 @@ type Config struct { } // fprint implements Fprint and takes a nodesSizes map for setting up the printer state. -func (cfg *Config) fprint(output io.Writer, fset *token.FileSet, node interface{}, nodeSizes map[ast.Node]int) (written int, err error) { +func (cfg *Config) fprint(output io.Writer, fset *token.FileSet, node interface{}, nodeSizes map[ast.Node]int) (err error) { + // print node + var p printer + p.init(cfg, fset, nodeSizes) + if err = p.printNode(node); err != nil { + return + } + p.flush(token.Position{Offset: infinity, Line: infinity}, token.EOF) + // redirect output through a trimmer to eliminate trailing whitespace // (Input to a tabwriter must be untrimmed since trailing tabs provide // formatting information. The tabwriter could provide trimming // functionality but no tabwriter is used when RawFormat is set.) output = &trimmer{output: output} - // setup tabwriter if needed and redirect output - var tw *tabwriter.Writer + // redirect output through a tabwriter if necessary if cfg.Mode&RawFormat == 0 { minwidth := cfg.Tabwidth @@ -980,63 +985,28 @@ func (cfg *Config) fprint(output io.Writer, fset *token.FileSet, node interface{ twmode |= tabwriter.TabIndent } - tw = tabwriter.NewWriter(output, minwidth, cfg.Tabwidth, 1, padchar, twmode) - output = tw + output = tabwriter.NewWriter(output, minwidth, cfg.Tabwidth, 1, padchar, twmode) } - // setup printer - var p printer - p.init(output, cfg, fset, nodeSizes) - defer func() { - written = p.written - if e := recover(); e != nil { - err = e.(osError).err // re-panics if it's not a local osError - } - }() - - // print node - switch n := node.(type) { - case ast.Expr: - p.useNodeComments = true - p.expr(n, ignoreMultiLine) - case ast.Stmt: - p.useNodeComments = true - // A labeled statement will un-indent to position the - // label. Set indent to 1 so we don't get indent "underflow". - if _, labeledStmt := n.(*ast.LabeledStmt); labeledStmt { - p.indent = 1 - } - p.stmt(n, false, ignoreMultiLine) - case ast.Decl: - p.useNodeComments = true - p.decl(n, ignoreMultiLine) - case ast.Spec: - p.useNodeComments = true - p.spec(n, 1, false, ignoreMultiLine) - case *ast.File: - p.comments = n.Comments - p.useNodeComments = n.Comments == nil - p.file(n) - default: - panic(osError{fmt.Errorf("printer.Fprint: unsupported node type %T", n)}) + // write printer result via tabwriter/trimmer to output + if _, err = output.Write(p.output.Bytes()); err != nil { + return } - p.flush(token.Position{Offset: infinity, Line: infinity}, token.EOF) // flush tabwriter, if any - if tw != nil { - tw.Flush() // ignore errors + if tw, _ := (output).(*tabwriter.Writer); tw != nil { + err = tw.Flush() } return } -// Fprint "pretty-prints" an AST node to output and returns the number -// of bytes written and an error (if any) for a given configuration cfg. +// Fprint "pretty-prints" an AST node to output for a given configuration cfg. // Position information is interpreted relative to the file set fset. // The node type must be *ast.File, or assignment-compatible to ast.Expr, // ast.Decl, ast.Spec, or ast.Stmt. // -func (cfg *Config) Fprint(output io.Writer, fset *token.FileSet, node interface{}) (int, error) { +func (cfg *Config) Fprint(output io.Writer, fset *token.FileSet, node interface{}) error { return cfg.fprint(output, fset, node, make(map[ast.Node]int)) } @@ -1044,6 +1014,5 @@ func (cfg *Config) Fprint(output io.Writer, fset *token.FileSet, node interface{ // It calls Config.Fprint with default settings. // func Fprint(output io.Writer, fset *token.FileSet, node interface{}) error { - _, err := (&Config{Tabwidth: 8}).Fprint(output, fset, node) // don't care about number of bytes written - return err + return (&Config{Tabwidth: 8}).Fprint(output, fset, node) } diff --git a/libgo/go/go/printer/printer_test.go b/libgo/go/go/printer/printer_test.go index a644aa383ab..924d4dfdb29 100644 --- a/libgo/go/go/printer/printer_test.go +++ b/libgo/go/go/printer/printer_test.go @@ -62,7 +62,7 @@ func runcheck(t *testing.T, source, golden string, mode checkMode) { // format source var buf bytes.Buffer - if _, err := cfg.Fprint(&buf, fset, prog); err != nil { + if err := cfg.Fprint(&buf, fset, prog); err != nil { t.Error(err) } res := buf.Bytes() diff --git a/libgo/go/hash/adler32/adler32.go b/libgo/go/hash/adler32/adler32.go index 10bed2f05e4..8103a89d439 100644 --- a/libgo/go/hash/adler32/adler32.go +++ b/libgo/go/hash/adler32/adler32.go @@ -71,14 +71,13 @@ func (d *digest) Write(p []byte) (nn int, err error) { func (d *digest) Sum32() uint32 { return finish(d.a, d.b) } -func (d *digest) Sum() []byte { - p := make([]byte, 4) +func (d *digest) Sum(in []byte) []byte { s := d.Sum32() - p[0] = byte(s >> 24) - p[1] = byte(s >> 16) - p[2] = byte(s >> 8) - p[3] = byte(s) - return p + in = append(in, byte(s>>24)) + in = append(in, byte(s>>16)) + in = append(in, byte(s>>8)) + in = append(in, byte(s)) + return in } // Checksum returns the Adler-32 checksum of data. diff --git a/libgo/go/hash/crc32/crc32.go b/libgo/go/hash/crc32/crc32.go index 5980ec0dc98..557fab8a52e 100644 --- a/libgo/go/hash/crc32/crc32.go +++ b/libgo/go/hash/crc32/crc32.go @@ -119,14 +119,13 @@ func (d *digest) Write(p []byte) (n int, err error) { func (d *digest) Sum32() uint32 { return d.crc } -func (d *digest) Sum() []byte { - p := make([]byte, 4) +func (d *digest) Sum(in []byte) []byte { s := d.Sum32() - p[0] = byte(s >> 24) - p[1] = byte(s >> 16) - p[2] = byte(s >> 8) - p[3] = byte(s) - return p + in = append(in, byte(s>>24)) + in = append(in, byte(s>>16)) + in = append(in, byte(s>>8)) + in = append(in, byte(s)) + return in } // Checksum returns the CRC-32 checksum of data diff --git a/libgo/go/hash/crc64/crc64.go b/libgo/go/hash/crc64/crc64.go index 42e53c3a5bd..e5c1db4b3d2 100644 --- a/libgo/go/hash/crc64/crc64.go +++ b/libgo/go/hash/crc64/crc64.go @@ -75,18 +75,17 @@ func (d *digest) Write(p []byte) (n int, err error) { func (d *digest) Sum64() uint64 { return d.crc } -func (d *digest) Sum() []byte { - p := make([]byte, 8) +func (d *digest) Sum(in []byte) []byte { s := d.Sum64() - p[0] = byte(s >> 56) - p[1] = byte(s >> 48) - p[2] = byte(s >> 40) - p[3] = byte(s >> 32) - p[4] = byte(s >> 24) - p[5] = byte(s >> 16) - p[6] = byte(s >> 8) - p[7] = byte(s) - return p + in = append(in, byte(s>>56)) + in = append(in, byte(s>>48)) + in = append(in, byte(s>>40)) + in = append(in, byte(s>>32)) + in = append(in, byte(s>>24)) + in = append(in, byte(s>>16)) + in = append(in, byte(s>>8)) + in = append(in, byte(s)) + return in } // Checksum returns the CRC-64 checksum of data diff --git a/libgo/go/hash/fnv/fnv.go b/libgo/go/hash/fnv/fnv.go index ce3ed0d0f40..2c8a25118e2 100644 --- a/libgo/go/hash/fnv/fnv.go +++ b/libgo/go/hash/fnv/fnv.go @@ -8,7 +8,6 @@ package fnv import ( - "encoding/binary" "hash" ) @@ -105,26 +104,46 @@ func (s *sum32a) Size() int { return 4 } func (s *sum64) Size() int { return 8 } func (s *sum64a) Size() int { return 8 } -func (s *sum32) Sum() []byte { - a := make([]byte, 4) - binary.BigEndian.PutUint32(a, uint32(*s)) - return a +func (s *sum32) Sum(in []byte) []byte { + v := uint32(*s) + in = append(in, byte(v>>24)) + in = append(in, byte(v>>16)) + in = append(in, byte(v>>8)) + in = append(in, byte(v)) + return in } -func (s *sum32a) Sum() []byte { - a := make([]byte, 4) - binary.BigEndian.PutUint32(a, uint32(*s)) - return a +func (s *sum32a) Sum(in []byte) []byte { + v := uint32(*s) + in = append(in, byte(v>>24)) + in = append(in, byte(v>>16)) + in = append(in, byte(v>>8)) + in = append(in, byte(v)) + return in } -func (s *sum64) Sum() []byte { - a := make([]byte, 8) - binary.BigEndian.PutUint64(a, uint64(*s)) - return a +func (s *sum64) Sum(in []byte) []byte { + v := uint64(*s) + in = append(in, byte(v>>56)) + in = append(in, byte(v>>48)) + in = append(in, byte(v>>40)) + in = append(in, byte(v>>32)) + in = append(in, byte(v>>24)) + in = append(in, byte(v>>16)) + in = append(in, byte(v>>8)) + in = append(in, byte(v)) + return in } -func (s *sum64a) Sum() []byte { - a := make([]byte, 8) - binary.BigEndian.PutUint64(a, uint64(*s)) - return a +func (s *sum64a) Sum(in []byte) []byte { + v := uint64(*s) + in = append(in, byte(v>>56)) + in = append(in, byte(v>>48)) + in = append(in, byte(v>>40)) + in = append(in, byte(v>>32)) + in = append(in, byte(v>>24)) + in = append(in, byte(v>>16)) + in = append(in, byte(v>>8)) + in = append(in, byte(v)) + return in } diff --git a/libgo/go/hash/fnv/fnv_test.go b/libgo/go/hash/fnv/fnv_test.go index 429230c80b4..17454deda90 100644 --- a/libgo/go/hash/fnv/fnv_test.go +++ b/libgo/go/hash/fnv/fnv_test.go @@ -72,7 +72,7 @@ func testGolden(t *testing.T, hash hash.Hash, gold []golden) { if done != len(g.text) { t.Fatalf("wrote only %d out of %d bytes", done, len(g.text)) } - if actual := hash.Sum(); !bytes.Equal(g.sum, actual) { + if actual := hash.Sum(nil); !bytes.Equal(g.sum, actual) { t.Errorf("hash(%q) = 0x%x want 0x%x", g.text, actual, g.sum) } } @@ -97,26 +97,26 @@ func TestIntegrity64a(t *testing.T) { func testIntegrity(t *testing.T, h hash.Hash) { data := []byte{'1', '2', 3, 4, 5} h.Write(data) - sum := h.Sum() + sum := h.Sum(nil) if size := h.Size(); size != len(sum) { t.Fatalf("Size()=%d but len(Sum())=%d", size, len(sum)) } - if a := h.Sum(); !bytes.Equal(sum, a) { + if a := h.Sum(nil); !bytes.Equal(sum, a) { t.Fatalf("first Sum()=0x%x, second Sum()=0x%x", sum, a) } h.Reset() h.Write(data) - if a := h.Sum(); !bytes.Equal(sum, a) { + if a := h.Sum(nil); !bytes.Equal(sum, a) { t.Fatalf("Sum()=0x%x, but after Reset() Sum()=0x%x", sum, a) } h.Reset() h.Write(data[:2]) h.Write(data[2:]) - if a := h.Sum(); !bytes.Equal(sum, a) { + if a := h.Sum(nil); !bytes.Equal(sum, a) { t.Fatalf("Sum()=0x%x, but with partial writes, Sum()=0x%x", sum, a) } @@ -162,6 +162,6 @@ func benchmark(b *testing.B, h hash.Hash) { for todo := b.N; todo != 0; todo-- { h.Reset() h.Write(data) - h.Sum() + h.Sum(nil) } } diff --git a/libgo/go/hash/hash.go b/libgo/go/hash/hash.go index 3536c0b6a64..0d7765dc505 100644 --- a/libgo/go/hash/hash.go +++ b/libgo/go/hash/hash.go @@ -13,9 +13,9 @@ type Hash interface { // It never returns an error. io.Writer - // Sum returns the current hash, without changing the - // underlying hash state. - Sum() []byte + // Sum appends the current hash in the same manner as append(), without + // changing the underlying hash state. + Sum(in []byte) []byte // Reset resets the hash to one with zero bytes written. Reset() diff --git a/libgo/go/html/doctype.go b/libgo/go/html/doctype.go new file mode 100644 index 00000000000..f692061a551 --- /dev/null +++ b/libgo/go/html/doctype.go @@ -0,0 +1,156 @@ +// 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 html + +import ( + "strings" +) + +// parseDoctype parses the data from a DoctypeToken into a name, +// public identifier, and system identifier. It returns a Node whose Type +// is DoctypeNode, whose Data is the name, and which has attributes +// named "system" and "public" for the two identifiers if they were present. +// quirks is whether the document should be parsed in "quirks mode". +func parseDoctype(s string) (n *Node, quirks bool) { + n = &Node{Type: DoctypeNode} + + // Find the name. + space := strings.IndexAny(s, whitespace) + if space == -1 { + space = len(s) + } + n.Data = s[:space] + // The comparison to "html" is case-sensitive. + if n.Data != "html" { + quirks = true + } + n.Data = strings.ToLower(n.Data) + s = strings.TrimLeft(s[space:], whitespace) + + if len(s) < 6 { + // It can't start with "PUBLIC" or "SYSTEM". + // Ignore the rest of the string. + return n, quirks || s != "" + } + + key := strings.ToLower(s[:6]) + s = s[6:] + for key == "public" || key == "system" { + s = strings.TrimLeft(s, whitespace) + if s == "" { + break + } + quote := s[0] + if quote != '"' && quote != '\'' { + break + } + s = s[1:] + q := strings.IndexRune(s, rune(quote)) + var id string + if q == -1 { + id = s + s = "" + } else { + id = s[:q] + s = s[q+1:] + } + n.Attr = append(n.Attr, Attribute{Key: key, Val: id}) + if key == "public" { + key = "system" + } else { + key = "" + } + } + + if key != "" || s != "" { + quirks = true + } else if len(n.Attr) > 0 { + if n.Attr[0].Key == "public" { + public := strings.ToLower(n.Attr[0].Val) + switch public { + case "-//w3o//dtd w3 html strict 3.0//en//", "-/w3d/dtd html 4.0 transitional/en", "html": + quirks = true + default: + for _, q := range quirkyIDs { + if strings.HasPrefix(public, q) { + quirks = true + break + } + } + } + // The following two public IDs only cause quirks mode if there is no system ID. + if len(n.Attr) == 1 && (strings.HasPrefix(public, "-//w3c//dtd html 4.01 frameset//") || + strings.HasPrefix(public, "-//w3c//dtd html 4.01 transitional//")) { + quirks = true + } + } + if lastAttr := n.Attr[len(n.Attr)-1]; lastAttr.Key == "system" && + strings.ToLower(lastAttr.Val) == "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd" { + quirks = true + } + } + + return n, quirks +} + +// quirkyIDs is a list of public doctype identifiers that cause a document +// to be interpreted in quirks mode. The identifiers should be in lower case. +var quirkyIDs = []string{ + "+//silmaril//dtd html pro v0r11 19970101//", + "-//advasoft ltd//dtd html 3.0 aswedit + extensions//", + "-//as//dtd html 3.0 aswedit + extensions//", + "-//ietf//dtd html 2.0 level 1//", + "-//ietf//dtd html 2.0 level 2//", + "-//ietf//dtd html 2.0 strict level 1//", + "-//ietf//dtd html 2.0 strict level 2//", + "-//ietf//dtd html 2.0 strict//", + "-//ietf//dtd html 2.0//", + "-//ietf//dtd html 2.1e//", + "-//ietf//dtd html 3.0//", + "-//ietf//dtd html 3.2 final//", + "-//ietf//dtd html 3.2//", + "-//ietf//dtd html 3//", + "-//ietf//dtd html level 0//", + "-//ietf//dtd html level 1//", + "-//ietf//dtd html level 2//", + "-//ietf//dtd html level 3//", + "-//ietf//dtd html strict level 0//", + "-//ietf//dtd html strict level 1//", + "-//ietf//dtd html strict level 2//", + "-//ietf//dtd html strict level 3//", + "-//ietf//dtd html strict//", + "-//ietf//dtd html//", + "-//metrius//dtd metrius presentational//", + "-//microsoft//dtd internet explorer 2.0 html strict//", + "-//microsoft//dtd internet explorer 2.0 html//", + "-//microsoft//dtd internet explorer 2.0 tables//", + "-//microsoft//dtd internet explorer 3.0 html strict//", + "-//microsoft//dtd internet explorer 3.0 html//", + "-//microsoft//dtd internet explorer 3.0 tables//", + "-//netscape comm. corp.//dtd html//", + "-//netscape comm. corp.//dtd strict html//", + "-//o'reilly and associates//dtd html 2.0//", + "-//o'reilly and associates//dtd html extended 1.0//", + "-//o'reilly and associates//dtd html extended relaxed 1.0//", + "-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//", + "-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//", + "-//spyglass//dtd html 2.0 extended//", + "-//sq//dtd html 2.0 hotmetal + extensions//", + "-//sun microsystems corp.//dtd hotjava html//", + "-//sun microsystems corp.//dtd hotjava strict html//", + "-//w3c//dtd html 3 1995-03-24//", + "-//w3c//dtd html 3.2 draft//", + "-//w3c//dtd html 3.2 final//", + "-//w3c//dtd html 3.2//", + "-//w3c//dtd html 3.2s draft//", + "-//w3c//dtd html 4.0 frameset//", + "-//w3c//dtd html 4.0 transitional//", + "-//w3c//dtd html experimental 19960712//", + "-//w3c//dtd html experimental 970421//", + "-//w3c//dtd w3 html//", + "-//w3o//dtd w3 html 3.0//", + "-//webtechs//dtd mozilla html 2.0//", + "-//webtechs//dtd mozilla html//", +} diff --git a/libgo/go/html/parse.go b/libgo/go/html/parse.go index 9b7e934ac34..97fbc514d82 100644 --- a/libgo/go/html/parse.go +++ b/libgo/go/html/parse.go @@ -37,6 +37,11 @@ type parser struct { // fosterParenting is whether new elements should be inserted according to // the foster parenting rules (section 11.2.5.3). fosterParenting bool + // quirks is whether the parser is operating in "quirks mode." + quirks bool + // context is the context element when parsing an HTML fragment + // (section 11.4). + context *Node } func (p *parser) top() *Node { @@ -285,9 +290,10 @@ func (p *parser) setOriginalIM() { func (p *parser) resetInsertionMode() { for i := len(p.oe) - 1; i >= 0; i-- { n := p.oe[i] - if i == 0 { - // TODO: set n to the context element, for HTML fragment parsing. + if i == 0 && p.context != nil { + n = p.context } + switch n.Data { case "select": p.im = inSelectIM @@ -319,9 +325,17 @@ func (p *parser) resetInsertionMode() { p.im = inBodyIM } +const whitespace = " \t\r\n\f" + // Section 11.2.5.4.1. func initialIM(p *parser) bool { switch p.tok.Type { + case TextToken: + p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace) + if len(p.tok.Data) == 0 { + // It was all whitespace, so ignore it. + return true + } case CommentToken: p.doc.Add(&Node{ Type: CommentNode, @@ -329,15 +343,13 @@ func initialIM(p *parser) bool { }) return true case DoctypeToken: - p.doc.Add(&Node{ - Type: DoctypeNode, - Data: p.tok.Data, - }) + n, quirks := parseDoctype(p.tok.Data) + p.doc.Add(n) + p.quirks = quirks p.im = beforeHTMLIM return true } - // TODO: set "quirks mode"? It's defined in the DOM spec instead of HTML5 proper, - // and so switching on "quirks mode" might belong in a different package. + p.quirks = true p.im = beforeHTMLIM return false } @@ -345,6 +357,12 @@ func initialIM(p *parser) bool { // Section 11.2.5.4.2. func beforeHTMLIM(p *parser) bool { switch p.tok.Type { + case TextToken: + p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace) + if len(p.tok.Data) == 0 { + // It was all whitespace, so ignore it. + return true + } case StartTagToken: if p.tok.Data == "html" { p.addElement(p.tok.Data, p.tok.Attr) @@ -383,7 +401,11 @@ func beforeHeadIM(p *parser) bool { case ErrorToken: implied = true case TextToken: - // TODO: distinguish whitespace text from others. + p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace) + if len(p.tok.Data) == 0 { + // It was all whitespace, so ignore it. + return true + } implied = true case StartTagToken: switch p.tok.Data { @@ -417,8 +439,6 @@ func beforeHeadIM(p *parser) bool { return !implied } -const whitespace = " \t\r\n\f" - // Section 11.2.5.4.4. func inHeadIM(p *parser) bool { var ( @@ -441,6 +461,8 @@ func inHeadIM(p *parser) bool { implied = true case StartTagToken: switch p.tok.Data { + case "html": + return inBodyIM(p) case "base", "basefont", "bgsound", "command", "link", "meta": p.addElement(p.tok.Data, p.tok.Attr) p.oe.pop() @@ -450,6 +472,9 @@ func inHeadIM(p *parser) bool { p.setOriginalIM() p.im = textIM return true + case "head": + // Ignore the token. + return true default: implied = true } @@ -560,11 +585,30 @@ func copyAttributes(dst *Node, src Token) { func inBodyIM(p *parser) bool { switch p.tok.Type { case TextToken: + switch n := p.oe.top(); n.Data { + case "pre", "listing", "textarea": + if len(n.Child) == 0 { + // Ignore a newline at the start of a
 block.
+				d := p.tok.Data
+				if d != "" && d[0] == '\r' {
+					d = d[1:]
+				}
+				if d != "" && d[0] == '\n' {
+					d = d[1:]
+				}
+				if d == "" {
+					return true
+				}
+				p.tok.Data = d
+			}
+		}
 		p.reconstructActiveFormattingElements()
 		p.addText(p.tok.Data)
 		p.framesetOK = false
 	case StartTagToken:
 		switch p.tok.Data {
+		case "html":
+			copyAttributes(p.oe[0], p.tok)
 		case "address", "article", "aside", "blockquote", "center", "details", "dir", "div", "dl", "fieldset", "figcaption", "figure", "footer", "header", "hgroup", "menu", "nav", "ol", "p", "section", "summary", "ul":
 			p.popUntil(buttonScopeStopTags, "p")
 			p.addElement(p.tok.Data, p.tok.Attr)
@@ -589,6 +633,13 @@ func inBodyIM(p *parser) bool {
 		case "b", "big", "code", "em", "font", "i", "s", "small", "strike", "strong", "tt", "u":
 			p.reconstructActiveFormattingElements()
 			p.addFormattingElement(p.tok.Data, p.tok.Attr)
+		case "nobr":
+			p.reconstructActiveFormattingElements()
+			if p.elementInScope(defaultScopeStopTags, "nobr") {
+				p.inBodyEndTagFormatting("nobr")
+				p.reconstructActiveFormattingElements()
+			}
+			p.addFormattingElement(p.tok.Data, p.tok.Attr)
 		case "applet", "marquee", "object":
 			p.reconstructActiveFormattingElements()
 			p.addElement(p.tok.Data, p.tok.Attr)
@@ -601,7 +652,9 @@ func inBodyIM(p *parser) bool {
 			p.acknowledgeSelfClosingTag()
 			p.framesetOK = false
 		case "table":
-			p.popUntil(buttonScopeStopTags, "p") // TODO: skip this step in quirks mode.
+			if !p.quirks {
+				p.popUntil(buttonScopeStopTags, "p")
+			}
 			p.addElement(p.tok.Data, p.tok.Attr)
 			p.framesetOK = false
 			p.im = inTableIM
@@ -721,6 +774,11 @@ func inBodyIM(p *parser) bool {
 			p.oe.pop()
 			p.oe.pop()
 			p.form = nil
+		case "xmp":
+			p.popUntil(buttonScopeStopTags, "p")
+			p.reconstructActiveFormattingElements()
+			p.framesetOK = false
+			p.addElement(p.tok.Data, p.tok.Attr)
 		case "caption", "col", "colgroup", "frame", "head", "tbody", "td", "tfoot", "th", "thead", "tr":
 			// Ignore the token.
 		default:
@@ -1462,6 +1520,29 @@ func afterAfterFramesetIM(p *parser) bool {
 	return true
 }
 
+func (p *parser) parse() error {
+	// Iterate until EOF. Any other error will cause an early return.
+	consumed := true
+	for {
+		if consumed {
+			if err := p.read(); err != nil {
+				if err == io.EOF {
+					break
+				}
+				return err
+			}
+		}
+		consumed = p.im(p)
+	}
+	// Loop until the final token (the ErrorToken signifying EOF) is consumed.
+	for {
+		if consumed = p.im(p); consumed {
+			break
+		}
+	}
+	return nil
+}
+
 // Parse returns the parse tree for the HTML from the given Reader.
 // The input is assumed to be UTF-8 encoded.
 func Parse(r io.Reader) (*Node, error) {
@@ -1474,24 +1555,62 @@ func Parse(r io.Reader) (*Node, error) {
 		framesetOK: true,
 		im:         initialIM,
 	}
-	// Iterate until EOF. Any other error will cause an early return.
-	consumed := true
-	for {
-		if consumed {
-			if err := p.read(); err != nil {
-				if err == io.EOF {
-					break
-				}
-				return nil, err
-			}
-		}
-		consumed = p.im(p)
-	}
-	// Loop until the final token (the ErrorToken signifying EOF) is consumed.
-	for {
-		if consumed = p.im(p); consumed {
-			break
-		}
+	err := p.parse()
+	if err != nil {
+		return nil, err
 	}
 	return p.doc, nil
 }
+
+// ParseFragment parses a fragment of HTML and returns the nodes that were 
+// found. If the fragment is the InnerHTML for an existing element, pass that
+// element in context.
+func ParseFragment(r io.Reader, context *Node) ([]*Node, error) {
+	p := &parser{
+		tokenizer: NewTokenizer(r),
+		doc: &Node{
+			Type: DocumentNode,
+		},
+		scripting: true,
+		context:   context,
+	}
+
+	if context != nil {
+		switch context.Data {
+		case "iframe", "noembed", "noframes", "noscript", "plaintext", "script", "style", "title", "textarea", "xmp":
+			p.tokenizer.rawTag = context.Data
+		}
+	}
+
+	root := &Node{
+		Type: ElementNode,
+		Data: "html",
+	}
+	p.doc.Add(root)
+	p.oe = nodeStack{root}
+	p.resetInsertionMode()
+
+	for n := context; n != nil; n = n.Parent {
+		if n.Type == ElementNode && n.Data == "form" {
+			p.form = n
+			break
+		}
+	}
+
+	err := p.parse()
+	if err != nil {
+		return nil, err
+	}
+
+	parent := p.doc
+	if context != nil {
+		parent = root
+	}
+
+	result := parent.Child
+	parent.Child = nil
+	for _, n := range result {
+		n.Parent = nil
+	}
+	return result, nil
+}
diff --git a/libgo/go/html/parse_test.go b/libgo/go/html/parse_test.go
index 4f15ae1d554..e0c19cff6da 100644
--- a/libgo/go/html/parse_test.go
+++ b/libgo/go/html/parse_test.go
@@ -10,65 +10,77 @@ import (
 	"errors"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"os"
 	"strings"
 	"testing"
 )
 
-func pipeErr(err error) io.Reader {
-	pr, pw := io.Pipe()
-	pw.CloseWithError(err)
-	return pr
-}
-
-func readDat(filename string, c chan io.Reader) {
-	defer close(c)
-	f, err := os.Open("testdata/webkit/" + filename)
+// readParseTest reads a single test case from r.
+func readParseTest(r *bufio.Reader) (text, want, context string, err error) {
+	line, err := r.ReadSlice('\n')
 	if err != nil {
-		c <- pipeErr(err)
-		return
+		return "", "", "", err
 	}
-	defer f.Close()
+	var b []byte
 
-	// Loop through the lines of the file. Each line beginning with "#" denotes
-	// a new section, which is returned as a separate io.Reader.
-	r := bufio.NewReader(f)
-	var pw *io.PipeWriter
+	// Read the HTML.
+	if string(line) != "#data\n" {
+		return "", "", "", fmt.Errorf(`got %q want "#data\n"`, line)
+	}
 	for {
-		line, err := r.ReadSlice('\n')
+		line, err = r.ReadSlice('\n')
 		if err != nil {
-			if pw != nil {
-				pw.CloseWithError(err)
-				pw = nil
-			} else {
-				c <- pipeErr(err)
-			}
-			return
-		}
-		if len(line) == 0 {
-			continue
+			return "", "", "", err
 		}
 		if line[0] == '#' {
-			if pw != nil {
-				pw.Close()
-			}
-			var pr *io.PipeReader
-			pr, pw = io.Pipe()
-			c <- pr
-			continue
+			break
 		}
-		if line[0] != '|' {
-			// Strip the trailing '\n'.
-			line = line[:len(line)-1]
+		b = append(b, line...)
+	}
+	text = strings.TrimRight(string(b), "\n")
+	b = b[:0]
+
+	// Skip the error list.
+	if string(line) != "#errors\n" {
+		return "", "", "", fmt.Errorf(`got %q want "#errors\n"`, line)
+	}
+	for {
+		line, err = r.ReadSlice('\n')
+		if err != nil {
+			return "", "", "", err
 		}
-		if pw != nil {
-			if _, err := pw.Write(line); err != nil {
-				pw.CloseWithError(err)
-				pw = nil
-			}
+		if line[0] == '#' {
+			break
 		}
 	}
+
+	if string(line) == "#document-fragment\n" {
+		line, err = r.ReadSlice('\n')
+		if err != nil {
+			return "", "", "", err
+		}
+		context = strings.TrimSpace(string(line))
+		line, err = r.ReadSlice('\n')
+		if err != nil {
+			return "", "", "", err
+		}
+	}
+
+	// Read the dump of what the parse tree should be.
+	if string(line) != "#document\n" {
+		return "", "", "", fmt.Errorf(`got %q want "#document\n"`, line)
+	}
+	for {
+		line, err = r.ReadSlice('\n')
+		if err != nil && err != io.EOF {
+			return "", "", "", err
+		}
+		if len(line) == 0 || len(line) == 1 && line[0] == '\n' {
+			break
+		}
+		b = append(b, line...)
+	}
+	return text, string(b), context, nil
 }
 
 func dumpIndent(w io.Writer, level int) {
@@ -93,11 +105,27 @@ func dumpLevel(w io.Writer, n *Node, level int) error {
 			fmt.Fprintf(w, `%s="%s"`, a.Key, a.Val)
 		}
 	case TextNode:
-		fmt.Fprintf(w, "%q", n.Data)
+		fmt.Fprintf(w, `"%s"`, n.Data)
 	case CommentNode:
 		fmt.Fprintf(w, "", n.Data)
 	case DoctypeNode:
-		fmt.Fprintf(w, "", n.Data)
+		fmt.Fprintf(w, "")
 	case scopeMarkerNode:
 		return errors.New("unexpected scopeMarkerNode")
 	default:
@@ -133,46 +161,62 @@ func TestParser(t *testing.T) {
 		n int
 	}{
 		// TODO(nigeltao): Process all the test cases from all the .dat files.
+		{"doctype01.dat", -1},
 		{"tests1.dat", -1},
-		{"tests2.dat", 43},
-		{"tests3.dat", 0},
+		{"tests2.dat", -1},
+		{"tests3.dat", -1},
+		{"tests4.dat", -1},
+		{"tests5.dat", -1},
 	}
 	for _, tf := range testFiles {
-		rc := make(chan io.Reader)
-		go readDat(tf.filename, rc)
+		f, err := os.Open("testdata/webkit/" + tf.filename)
+		if err != nil {
+			t.Fatal(err)
+		}
+		defer f.Close()
+		r := bufio.NewReader(f)
 		for i := 0; i != tf.n; i++ {
-			// Parse the #data section.
-			dataReader := <-rc
-			if dataReader == nil {
+			text, want, context, err := readParseTest(r)
+			if err == io.EOF && tf.n == -1 {
 				break
 			}
-			b, err := ioutil.ReadAll(dataReader)
 			if err != nil {
 				t.Fatal(err)
 			}
-			text := string(b)
-			doc, err := Parse(strings.NewReader(text))
-			if err != nil {
-				t.Fatal(err)
+
+			var doc *Node
+			if context == "" {
+				doc, err = Parse(strings.NewReader(text))
+				if err != nil {
+					t.Fatal(err)
+				}
+			} else {
+				contextNode := &Node{
+					Type: ElementNode,
+					Data: context,
+				}
+				nodes, err := ParseFragment(strings.NewReader(text), contextNode)
+				if err != nil {
+					t.Fatal(err)
+				}
+				doc = &Node{
+					Type: DocumentNode,
+				}
+				for _, n := range nodes {
+					doc.Add(n)
+				}
 			}
+
 			got, err := dump(doc)
 			if err != nil {
 				t.Fatal(err)
 			}
-			// Skip the #error section.
-			if _, err := io.Copy(ioutil.Discard, <-rc); err != nil {
-				t.Fatal(err)
-			}
 			// Compare the parsed tree to the #document section.
-			b, err = ioutil.ReadAll(<-rc)
-			if err != nil {
-				t.Fatal(err)
-			}
-			if want := string(b); got != want {
+			if got != want {
 				t.Errorf("%s test #%d %q, got vs want:\n----\n%s----\n%s----", tf.filename, i, text, got, want)
 				continue
 			}
-			if renderTestBlacklist[text] {
+			if renderTestBlacklist[text] || context != "" {
 				continue
 			}
 			// Check that rendering and re-parsing results in an identical tree.
@@ -193,12 +237,6 @@ func TestParser(t *testing.T) {
 				continue
 			}
 		}
-		// Drain any untested cases for the test file.
-		for r := range rc {
-			if _, err := ioutil.ReadAll(r); err != nil {
-				t.Fatal(err)
-			}
-		}
 	}
 }
 
diff --git a/libgo/go/html/render.go b/libgo/go/html/render.go
index 92c349fb32c..7e1a4669657 100644
--- a/libgo/go/html/render.go
+++ b/libgo/go/html/render.go
@@ -9,6 +9,7 @@ import (
 	"errors"
 	"fmt"
 	"io"
+	"strings"
 )
 
 type writer interface {
@@ -98,6 +99,40 @@ func render1(w writer, n *Node) error {
 		if _, err := w.WriteString(n.Data); err != nil {
 			return err
 		}
+		if n.Attr != nil {
+			var p, s string
+			for _, a := range n.Attr {
+				switch a.Key {
+				case "public":
+					p = a.Val
+				case "system":
+					s = a.Val
+				}
+			}
+			if p != "" {
+				if _, err := w.WriteString(" PUBLIC "); err != nil {
+					return err
+				}
+				if err := writeQuoted(w, p); err != nil {
+					return err
+				}
+				if s != "" {
+					if err := w.WriteByte(' '); err != nil {
+						return err
+					}
+					if err := writeQuoted(w, s); err != nil {
+						return err
+					}
+				}
+			} else if s != "" {
+				if _, err := w.WriteString(" SYSTEM "); err != nil {
+					return err
+				}
+				if err := writeQuoted(w, s); err != nil {
+					return err
+				}
+			}
+		}
 		return w.WriteByte('>')
 	default:
 		return errors.New("html: unknown node type")
@@ -138,9 +173,19 @@ func render1(w writer, n *Node) error {
 		return err
 	}
 
+	// Add initial newline where there is danger of a newline beging ignored.
+	if len(n.Child) > 0 && n.Child[0].Type == TextNode && strings.HasPrefix(n.Child[0].Data, "\n") {
+		switch n.Data {
+		case "pre", "listing", "textarea":
+			if err := w.WriteByte('\n'); err != nil {
+				return err
+			}
+		}
+	}
+
 	// Render any child nodes.
 	switch n.Data {
-	case "noembed", "noframes", "noscript", "plaintext", "script", "style":
+	case "iframe", "noembed", "noframes", "noscript", "plaintext", "script", "style", "xmp":
 		for _, c := range n.Child {
 			if c.Type != TextNode {
 				return fmt.Errorf("html: raw text element <%s> has non-text child node", n.Data)
@@ -181,6 +226,27 @@ func render1(w writer, n *Node) error {
 	return w.WriteByte('>')
 }
 
+// writeQuoted writes s to w surrounded by quotes. Normally it will use double
+// quotes, but if s contains a double quote, it will use single quotes.
+// It is used for writing the identifiers in a doctype declaration.
+// In valid HTML, they can't contain both types of quotes.
+func writeQuoted(w writer, s string) error {
+	var q byte = '"'
+	if strings.Contains(s, `"`) {
+		q = '\''
+	}
+	if err := w.WriteByte(q); err != nil {
+		return err
+	}
+	if _, err := w.WriteString(s); err != nil {
+		return err
+	}
+	if err := w.WriteByte(q); err != nil {
+		return err
+	}
+	return nil
+}
+
 // Section 13.1.2, "Elements", gives this list of void elements. Void elements
 // are those that can't have any contents.
 var voidElements = map[string]bool{
diff --git a/libgo/go/html/template/clone_test.go b/libgo/go/html/template/clone_test.go
index ed1698acd8b..39788173b99 100644
--- a/libgo/go/html/template/clone_test.go
+++ b/libgo/go/html/template/clone_test.go
@@ -7,8 +7,6 @@ package template
 import (
 	"bytes"
 	"testing"
-	"text/template"
-	"text/template/parse"
 )
 
 func TestClone(t *testing.T) {
@@ -48,15 +46,20 @@ func TestClone(t *testing.T) {
 	}
 
 	for _, test := range tests {
-		s := template.Must(template.New("s").Parse(test.input))
-		d := template.New("d")
-		d.Tree = &parse.Tree{Name: d.Name(), Root: cloneList(s.Root)}
+		s, err := New("s").Parse(test.input)
+		if err != nil {
+			t.Errorf("input=%q: unexpected parse error %v", test.input, err)
+		}
 
-		if want, got := s.Root.String(), d.Root.String(); want != got {
+		d, _ := New("d").Parse(test.input)
+		// Hack: just replace the root of the tree.
+		d.text.Root = cloneList(s.text.Root)
+
+		if want, got := s.text.Root.String(), d.text.Root.String(); want != got {
 			t.Errorf("want %q, got %q", want, got)
 		}
 
-		err := escape(d)
+		err = escapeTemplates(d, "d")
 		if err != nil {
 			t.Errorf("%q: failed to escape: %s", test.input, err)
 			continue
@@ -73,18 +76,17 @@ func TestClone(t *testing.T) {
 
 		data := []string{"foo", "", "baz"}
 
-		// Make sure escaping d did not affect s.
 		var b bytes.Buffer
-		s.Execute(&b, data)
-		if got := b.String(); got != test.want {
-			t.Errorf("%q: want %q, got %q", test.input, test.want, got)
-			continue
-		}
-
-		b.Reset()
 		d.Execute(&b, data)
 		if got := b.String(); got != test.wantClone {
-			t.Errorf("%q: want %q, got %q", test.input, test.wantClone, got)
+			t.Errorf("input=%q: want %q, got %q", test.input, test.wantClone, got)
+		}
+
+		// Make sure escaping d did not affect s.
+		b.Reset()
+		s.text.Execute(&b, data)
+		if got := b.String(); got != test.want {
+			t.Errorf("input=%q: want %q, got %q", test.input, test.want, got)
 		}
 	}
 }
diff --git a/libgo/go/html/template/content.go b/libgo/go/html/template/content.go
index 3fb15a6e93f..4de7ccde912 100644
--- a/libgo/go/html/template/content.go
+++ b/libgo/go/html/template/content.go
@@ -12,10 +12,10 @@ import (
 // Strings of content from a trusted source.
 type (
 	// CSS encapsulates known safe content that matches any of:
-	// (1) The CSS3 stylesheet production, such as `p { color: purple }`.
-	// (2) The CSS3 rule production, such as `a[href=~"https:"].foo#bar`.
-	// (3) CSS3 declaration productions, such as `color: red; margin: 2px`.
-	// (4) The CSS3 value production, such as `rgba(0, 0, 255, 127)`.
+	//   1. The CSS3 stylesheet production, such as `p { color: purple }`.
+	//   2. The CSS3 rule production, such as `a[href=~"https:"].foo#bar`.
+	//   3. CSS3 declaration productions, such as `color: red; margin: 2px`.
+	//   4. The CSS3 value production, such as `rgba(0, 0, 255, 127)`.
 	// See http://www.w3.org/TR/css3-syntax/#style
 	CSS string
 
@@ -41,8 +41,8 @@ type (
 	// JSStr encapsulates a sequence of characters meant to be embedded
 	// between quotes in a JavaScript expression.
 	// The string must match a series of StringCharacters:
-	// StringCharacter :: SourceCharacter but not `\` or LineTerminator
-	//                  | EscapeSequence
+	//   StringCharacter :: SourceCharacter but not `\` or LineTerminator
+	//                    | EscapeSequence
 	// Note that LineContinuations are not allowed.
 	// JSStr("foo\\nbar") is fine, but JSStr("foo\\\nbar") is not.
 	JSStr string
diff --git a/libgo/go/html/template/doc.go b/libgo/go/html/template/doc.go
index 0324c9c0ee3..fc0e3826442 100644
--- a/libgo/go/html/template/doc.go
+++ b/libgo/go/html/template/doc.go
@@ -13,9 +13,9 @@ Introduction
 This package wraps package template so you can use the standard template API
 to parse and execute templates.
 
-    set, err := new(template.Set).Parse(...)
-    // Error checking elided
-    err = set.Execute(out, "Foo", data)
+  set, err := new(template.Set).Parse(...)
+  // Error checking elided
+  err = set.Execute(out, "Foo", data)
 
 If successful, set will now be injection-safe. Otherwise, err is an error
 defined in the docs for ErrorCode.
@@ -29,25 +29,25 @@ trusted, while Execute's data parameter is not. More details are provided below.
 
 Example
 
-    import "template"
-    ...
-    t, err := (&template.Set{}).Parse(`{{define "T"}}Hello, {{.}}!{{end}}`)
-    err = t.Execute(out, "T", "")
+  import "text/template"
+  ...
+  t, err := (&template.Set{}).Parse(`{{define "T"}}Hello, {{.}}!{{end}}`)
+  err = t.Execute(out, "T", "")
 
 produces
 
-    Hello, !
+  Hello, !
 
 but with contextual autoescaping,
 
-    import "html/template"
-    ...
-    t, err := (&template.Set{}).Parse(`{{define "T"}}Hello, {{.}}!{{end}}`)
-    err = t.Execute(out, "T", "")
+  import "html/template"
+  ...
+  t, err := (&template.Set{}).Parse(`{{define "T"}}Hello, {{.}}!{{end}}`)
+  err = t.Execute(out, "T", "")
 
 produces safe, escaped HTML output
 
-    Hello, <script>alert('you have been pwned')</script>!
+  Hello, <script>alert('you have been pwned')</script>!
 
 
 Contexts
@@ -80,36 +80,36 @@ Contexts
 Assuming {{.}} is `O'Reilly: How are you?`, the table below shows
 how {{.}} appears when used in the context to the left.
 
-Context                          {{.}} After
-{{.}}                            O'Reilly: How are <i>you</i>?
-                O'Reilly: How are you?
-                O'Reilly: How are %3ci%3eyou%3c/i%3e?
-              O'Reilly%3a%20How%20are%3ci%3e...%3f
-             O\x27Reilly: How are \x3ci\x3eyou...?
-               "O\x27Reilly: How are \x3ci\x3eyou...?"
-     O\x27Reilly: How are \x3ci\x3eyou...\x3f
+  Context                          {{.}} After
+  {{.}}                            O'Reilly: How are <i>you</i>?
+                  O'Reilly: How are you?
+                  O'Reilly: How are %3ci%3eyou%3c/i%3e?
+                O'Reilly%3a%20How%20are%3ci%3e...%3f
+               O\x27Reilly: How are \x3ci\x3eyou...?
+                 "O\x27Reilly: How are \x3ci\x3eyou...?"
+       O\x27Reilly: How are \x3ci\x3eyou...\x3f
 
 If used in an unsafe context, then the value might be filtered out:
 
-Context                          {{.}} After
-                 #ZgotmplZ
+  Context                          {{.}} After
+                   #ZgotmplZ
 
 since "O'Reilly:" is not an allowed protocol like "http:".
 
 
 If {{.}} is the innocuous word, `left`, then it can appear more widely,
 
-Context                              {{.}} After
-{{.}}                                left
-                    left
-                     left
-                    left
-                left
-        left
-             left
-  left
-   left
+  Context                              {{.}} After
+  {{.}}                                left
+                      left
+                       left
+                      left
+                  left
+          left
+               left
+    left
+     left
 
 Non-string values can be used in JavaScript contexts.
 If {{.}} is
diff --git a/libgo/go/html/template/escape.go b/libgo/go/html/template/escape.go
index 8ac07eae24c..4a7a9354c93 100644
--- a/libgo/go/html/template/escape.go
+++ b/libgo/go/html/template/escape.go
@@ -12,24 +12,15 @@ import (
 	"text/template/parse"
 )
 
-// escape rewrites each action in the template to guarantee that the output is
-// properly escaped.
-func escape(t *template.Template) error {
-	var s template.Set
-	s.Add(t)
-	return escapeSet(&s, t.Name())
-	// TODO: if s contains cloned dependencies due to self-recursion
-	// cross-context, error out.
-}
-
-// escapeSet rewrites the template set to guarantee that the output of any of
-// the named templates is properly escaped.
-// Names should include the names of all templates that might be Executed but
-// need not include helper templates.
-// If no error is returned, then the named templates have been modified. 
-// Otherwise the named templates have been rendered unusable.
-func escapeSet(s *template.Set, names ...string) error {
-	e := newEscaper(s)
+// escapeTemplates rewrites the named templates, which must be
+// associated with t, to guarantee that the output of any of the named
+// templates is properly escaped.  Names should include the names of
+// all templates that might be Executed but need not include helper
+// templates.  If no error is returned, then the named templates have
+// been modified.  Otherwise the named templates have been rendered
+// unusable.
+func escapeTemplates(tmpl *Template, names ...string) error {
+	e := newEscaper(tmpl)
 	for _, name := range names {
 		c, _ := e.escapeTree(context{}, name, 0)
 		var err error
@@ -41,12 +32,13 @@ func escapeSet(s *template.Set, names ...string) error {
 		if err != nil {
 			// Prevent execution of unsafe templates.
 			for _, name := range names {
-				if t := s.Template(name); t != nil {
-					t.Tree = nil
+				if t := tmpl.set[name]; t != nil {
+					t.text.Tree = nil
 				}
 			}
 			return err
 		}
+		tmpl.escaped = true
 	}
 	e.commit()
 	return nil
@@ -83,8 +75,7 @@ var equivEscapers = map[string]string{
 // escaper collects type inferences about templates and changes needed to make
 // templates injection safe.
 type escaper struct {
-	// set is the template set being escaped.
-	set *template.Set
+	tmpl *Template
 	// output[templateName] is the output context for a templateName that
 	// has been mangled to include its input context.
 	output map[string]context
@@ -102,9 +93,9 @@ type escaper struct {
 }
 
 // newEscaper creates a blank escaper for the given set.
-func newEscaper(s *template.Set) *escaper {
+func newEscaper(t *Template) *escaper {
 	return &escaper{
-		s,
+		t,
 		map[string]context{},
 		map[string]*template.Template{},
 		map[string]bool{},
@@ -442,7 +433,7 @@ func (e *escaper) escapeList(c context, n *parse.ListNode) context {
 // It returns the best guess at an output context, and the result of the filter
 // which is the same as whether e was updated.
 func (e *escaper) escapeListConditionally(c context, n *parse.ListNode, filter func(*escaper, context) bool) (context, bool) {
-	e1 := newEscaper(e.set)
+	e1 := newEscaper(e.tmpl)
 	// Make type inferences available to f.
 	for k, v := range e.output {
 		e1.output[k] = v
@@ -501,7 +492,7 @@ func (e *escaper) escapeTree(c context, name string, line int) (context, string)
 		}, dname
 	}
 	if dname != name {
-		// Use any template derived during an earlier call to escapeSet
+		// Use any template derived during an earlier call to escapeTemplate
 		// with different top level templates, or clone if necessary.
 		dt := e.template(dname)
 		if dt == nil {
@@ -529,7 +520,7 @@ func (e *escaper) computeOutCtx(c context, t *template.Template) context {
 	if !ok && c1.state != stateError {
 		return context{
 			state: stateError,
-			// TODO: Find the first node with a line in t.Tree.Root
+			// TODO: Find the first node with a line in t.text.Tree.Root
 			err: errorf(ErrOutputContext, 0, "cannot compute output context for template %s", t.Name()),
 		}
 	}
@@ -729,7 +720,9 @@ func (e *escaper) commit() {
 		e.template(name).Funcs(funcMap)
 	}
 	for _, t := range e.derived {
-		e.set.Add(t)
+		if _, err := e.tmpl.text.AddParseTree(t.Name(), t.Tree); err != nil {
+			panic("error adding derived template")
+		}
 	}
 	for n, s := range e.actionNodeEdits {
 		ensurePipelineContains(n.Pipe, s)
@@ -744,7 +737,7 @@ func (e *escaper) commit() {
 
 // template returns the named template given a mangled template name.
 func (e *escaper) template(name string) *template.Template {
-	t := e.set.Template(name)
+	t := e.tmpl.text.Lookup(name)
 	if t == nil {
 		t = e.derived[name]
 	}
diff --git a/libgo/go/html/template/escape_test.go b/libgo/go/html/template/escape_test.go
index 4af583097bd..b4daca7d6bd 100644
--- a/libgo/go/html/template/escape_test.go
+++ b/libgo/go/html/template/escape_test.go
@@ -806,13 +806,15 @@ func TestEscapeSet(t *testing.T) {
 		for name, body := range test.inputs {
 			source += fmt.Sprintf("{{define %q}}%s{{end}} ", name, body)
 		}
-		s := &Set{}
-		s.Funcs(fns)
-		s.Parse(source)
+		tmpl, err := New("root").Funcs(fns).Parse(source)
+		if err != nil {
+			t.Errorf("error parsing %q: %v", source, err)
+			continue
+		}
 		var b bytes.Buffer
 
-		if err := s.Execute(&b, "main", data); err != nil {
-			t.Errorf("%q executing %v", err.Error(), s.Template("main"))
+		if err := tmpl.ExecuteTemplate(&b, "main", data); err != nil {
+			t.Errorf("%q executing %v", err.Error(), tmpl.Lookup("main"))
 			continue
 		}
 		if got := b.String(); test.want != got {
@@ -929,13 +931,13 @@ func TestErrors(t *testing.T) {
 			"z:1: no such template foo",
 		},
 		{
-			`{{define "z"}}{{end}}` +
+			`` +
 				// Illegal starting in stateTag but not in stateText.
 				`{{define "y"}} fooreverseList = [{{template "t"}}]{{end}}` +
+			`` +
 				// Missing " after recursive call.
 				`{{define "t"}}{{if .Tail}}{{template "t" .Tail}}{{end}}{{.Head}}",{{end}}`,
 			`: cannot compute output context for template t$htmltemplate_stateJS_elementScript`,
@@ -967,21 +969,13 @@ func TestErrors(t *testing.T) {
 	}
 
 	for _, test := range tests {
-		var err error
 		buf := new(bytes.Buffer)
-		if strings.HasPrefix(test.input, "{{define") {
-			var s *Set
-			s, err = (&Set{}).Parse(test.input)
-			if err == nil {
-				err = s.Execute(buf, "z", nil)
-			}
-		} else {
-			var t *Template
-			t, err = New("z").Parse(test.input)
-			if err == nil {
-				err = t.Execute(buf, nil)
-			}
+		tmpl, err := New("z").Parse(test.input)
+		if err != nil {
+			t.Errorf("input=%q: unexpected parse error %s\n", test.input, err)
+			continue
 		}
+		err = tmpl.Execute(buf, nil)
 		var got string
 		if err != nil {
 			got = err.Error()
@@ -1569,11 +1563,11 @@ func TestEscapeErrorsNotIgnorable(t *testing.T) {
 
 func TestEscapeSetErrorsNotIgnorable(t *testing.T) {
 	var b bytes.Buffer
-	s, err := (&Set{}).Parse(`{{define "t"}} 2 {
+				dashCount = 2
+			}
+			z.data.end = z.raw.end - dashCount
 			return
 		}
 		switch c {
@@ -375,6 +379,28 @@ func (z *Tokenizer) readMarkupDeclaration() TokenType {
 	return DoctypeToken
 }
 
+// startTagIn returns whether the start tag in z.buf[z.data.start:z.data.end]
+// case-insensitively matches any element of ss.
+func (z *Tokenizer) startTagIn(ss ...string) bool {
+loop:
+	for _, s := range ss {
+		if z.data.end-z.data.start != len(s) {
+			continue loop
+		}
+		for i := 0; i < len(s); i++ {
+			c := z.buf[z.data.start+i]
+			if 'A' <= c && c <= 'Z' {
+				c += 'a' - 'A'
+			}
+			if c != s[i] {
+				continue loop
+			}
+		}
+		return true
+	}
+	return false
+}
+
 // readStartTag reads the next start tag token. The opening "", "", "<noscript>", "<plaintext", "<script>", "<style>",
-	// "<textarea>" or "<title>" tag flags the tokenizer's next token as raw.
-	// The tag name lengths of these special cases ranges in [5, 9].
-	if x := z.data.end - z.data.start; 5 <= x && x <= 9 {
-		switch z.buf[z.data.start] {
-		case 'n', 'p', 's', 't', 'N', 'P', 'S', 'T':
-			switch s := strings.ToLower(string(z.buf[z.data.start:z.data.end])); s {
-			case "noembed", "noframes", "noscript", "plaintext", "script", "style", "textarea", "title":
-				z.rawTag = s
-			}
-		}
+	// Several tags flag the tokenizer's next token as raw.
+	c, raw := z.buf[z.data.start], false
+	if 'A' <= c && c <= 'Z' {
+		c += 'a' - 'A'
+	}
+	switch c {
+	case 'i':
+		raw = z.startTagIn("iframe")
+	case 'n':
+		raw = z.startTagIn("noembed", "noframes", "noscript")
+	case 'p':
+		raw = z.startTagIn("plaintext")
+	case 's':
+		raw = z.startTagIn("script", "style")
+	case 't':
+		raw = z.startTagIn("textarea", "title")
+	case 'x':
+		raw = z.startTagIn("xmp")
+	}
+	if raw {
+		z.rawTag = strings.ToLower(string(z.buf[z.data.start:z.data.end]))
 	}
 	// Look for a self-closing token like "<br/>".
 	if z.err == nil && z.buf[z.raw.end-2] == '/' {
diff --git a/libgo/go/html/token_test.go b/libgo/go/html/token_test.go
index 61d4e67c06d..672d60c4209 100644
--- a/libgo/go/html/token_test.go
+++ b/libgo/go/html/token_test.go
@@ -325,6 +325,26 @@ var tokenTests = []tokenTest{
 	},
 	{
 		"comment9",
+		"a<!--z-",
+		"a$<!--z-->",
+	},
+	{
+		"comment10",
+		"a<!--z--",
+		"a$<!--z-->",
+	},
+	{
+		"comment11",
+		"a<!--z---",
+		"a$<!--z--->",
+	},
+	{
+		"comment12",
+		"a<!--z----",
+		"a$<!--z---->",
+	},
+	{
+		"comment13",
 		"a<!--x--!>z",
 		"a$<!--x-->$z",
 	},
diff --git a/libgo/go/io/ioutil/ioutil.go b/libgo/go/io/ioutil/ioutil.go
index f6c8cd8a873..be7fa5f2bc8 100644
--- a/libgo/go/io/ioutil/ioutil.go
+++ b/libgo/go/io/ioutil/ioutil.go
@@ -36,8 +36,8 @@ func ReadFile(filename string) ([]byte, error) {
 	// read, so let's try it but be prepared for the answer to be wrong.
 	fi, err := f.Stat()
 	var n int64
-	if err == nil && fi.Size < 2e9 { // Don't preallocate a huge buffer, just in case.
-		n = fi.Size
+	if size := fi.Size(); err == nil && size < 2e9 { // Don't preallocate a huge buffer, just in case.
+		n = size
 	}
 	// As initial capacity for readAll, use n + a little extra in case Size is zero,
 	// and to avoid another allocation after Read has filled the buffer.  The readAll
@@ -63,16 +63,16 @@ func WriteFile(filename string, data []byte, perm uint32) error {
 	return err
 }
 
-// A fileInfoList implements sort.Interface.
-type fileInfoList []*os.FileInfo
+// byName implements sort.Interface.
+type byName []os.FileInfo
 
-func (f fileInfoList) Len() int           { return len(f) }
-func (f fileInfoList) Less(i, j int) bool { return f[i].Name < f[j].Name }
-func (f fileInfoList) Swap(i, j int)      { f[i], f[j] = f[j], f[i] }
+func (f byName) Len() int           { return len(f) }
+func (f byName) Less(i, j int) bool { return f[i].Name() < f[j].Name() }
+func (f byName) Swap(i, j int)      { f[i], f[j] = f[j], f[i] }
 
 // ReadDir reads the directory named by dirname and returns
 // a list of sorted directory entries.
-func ReadDir(dirname string) ([]*os.FileInfo, error) {
+func ReadDir(dirname string) ([]os.FileInfo, error) {
 	f, err := os.Open(dirname)
 	if err != nil {
 		return nil, err
@@ -82,12 +82,8 @@ func ReadDir(dirname string) ([]*os.FileInfo, error) {
 	if err != nil {
 		return nil, err
 	}
-	fi := make(fileInfoList, len(list))
-	for i := range list {
-		fi[i] = &list[i]
-	}
-	sort.Sort(fi)
-	return fi, nil
+	sort.Sort(byName(list))
+	return list, nil
 }
 
 type nopCloser struct {
diff --git a/libgo/go/io/ioutil/ioutil_test.go b/libgo/go/io/ioutil/ioutil_test.go
index 55e4b2c2bc8..89d6815ad50 100644
--- a/libgo/go/io/ioutil/ioutil_test.go
+++ b/libgo/go/io/ioutil/ioutil_test.go
@@ -15,8 +15,8 @@ func checkSize(t *testing.T, path string, size int64) {
 	if err != nil {
 		t.Fatalf("Stat %q (looking for size %d): %s", path, size, err)
 	}
-	if dir.Size != size {
-		t.Errorf("Stat %q: size %d want %d", path, dir.Size, size)
+	if dir.Size() != size {
+		t.Errorf("Stat %q: size %d want %d", path, dir.Size(), size)
 	}
 }
 
@@ -76,9 +76,9 @@ func TestReadDir(t *testing.T) {
 	foundTestDir := false
 	for _, dir := range list {
 		switch {
-		case dir.IsRegular() && dir.Name == "ioutil_test.go":
+		case !dir.IsDir() && dir.Name() == "ioutil_test.go":
 			foundTest = true
-		case dir.IsDirectory() && dir.Name == "_test":
+		case dir.IsDir() && dir.Name() == "_test":
 			foundTestDir = true
 		}
 	}
diff --git a/libgo/go/io/ioutil/tempfile.go b/libgo/go/io/ioutil/tempfile.go
index 71028e22677..645eed6abb8 100644
--- a/libgo/go/io/ioutil/tempfile.go
+++ b/libgo/go/io/ioutil/tempfile.go
@@ -18,7 +18,7 @@ import (
 var rand uint32
 
 func reseed() uint32 {
-	return uint32(time.Nanoseconds() + int64(os.Getpid()))
+	return uint32(time.Now().UnixNano() + int64(os.Getpid()))
 }
 
 func nextSuffix() string {
diff --git a/libgo/go/io/multi_test.go b/libgo/go/io/multi_test.go
index 0de5cc312d0..eb717f7bc21 100644
--- a/libgo/go/io/multi_test.go
+++ b/libgo/go/io/multi_test.go
@@ -77,7 +77,7 @@ func TestMultiWriter(t *testing.T) {
 		t.Errorf("unexpected error: %v", err)
 	}
 
-	sha1hex := fmt.Sprintf("%x", sha1.Sum())
+	sha1hex := fmt.Sprintf("%x", sha1.Sum(nil))
 	if sha1hex != "01cb303fa8c30a64123067c5aa6284ba7ec2d31b" {
 		t.Error("incorrect sha1 value")
 	}
diff --git a/libgo/go/log/log.go b/libgo/go/log/log.go
index b5368af5319..a5d88fd9b34 100644
--- a/libgo/go/log/log.go
+++ b/libgo/go/log/log.go
@@ -83,27 +83,28 @@ func itoa(buf *bytes.Buffer, i int, wid int) {
 	}
 }
 
-func (l *Logger) formatHeader(buf *bytes.Buffer, ns int64, file string, line int) {
+func (l *Logger) formatHeader(buf *bytes.Buffer, t time.Time, file string, line int) {
 	buf.WriteString(l.prefix)
 	if l.flag&(Ldate|Ltime|Lmicroseconds) != 0 {
-		t := time.SecondsToLocalTime(ns / 1e9)
 		if l.flag&Ldate != 0 {
-			itoa(buf, int(t.Year), 4)
+			year, month, day := t.Date()
+			itoa(buf, year, 4)
 			buf.WriteByte('/')
-			itoa(buf, int(t.Month), 2)
+			itoa(buf, int(month), 2)
 			buf.WriteByte('/')
-			itoa(buf, int(t.Day), 2)
+			itoa(buf, day, 2)
 			buf.WriteByte(' ')
 		}
 		if l.flag&(Ltime|Lmicroseconds) != 0 {
-			itoa(buf, int(t.Hour), 2)
+			hour, min, sec := t.Clock()
+			itoa(buf, hour, 2)
 			buf.WriteByte(':')
-			itoa(buf, int(t.Minute), 2)
+			itoa(buf, min, 2)
 			buf.WriteByte(':')
-			itoa(buf, int(t.Second), 2)
+			itoa(buf, sec, 2)
 			if l.flag&Lmicroseconds != 0 {
 				buf.WriteByte('.')
-				itoa(buf, int(ns%1e9)/1e3, 6)
+				itoa(buf, t.Nanosecond()/1e3, 6)
 			}
 			buf.WriteByte(' ')
 		}
@@ -133,7 +134,7 @@ func (l *Logger) formatHeader(buf *bytes.Buffer, ns int64, file string, line int
 // provided for generality, although at the moment on all pre-defined
 // paths it will be 2.
 func (l *Logger) Output(calldepth int, s string) error {
-	now := time.Nanoseconds() // get this early.
+	now := time.Now() // get this early.
 	var file string
 	var line int
 	l.mu.Lock()
diff --git a/libgo/go/math/abs.go b/libgo/go/math/abs.go
index eb3e4c72b32..4c6297c6f33 100644
--- a/libgo/go/math/abs.go
+++ b/libgo/go/math/abs.go
@@ -7,8 +7,7 @@ package math
 // Abs returns the absolute value of x.
 //
 // Special cases are:
-//	Abs(+Inf) = +Inf
-//	Abs(-Inf) = +Inf
+//	Abs(±Inf) = +Inf
 //	Abs(NaN) = NaN
 func Abs(x float64) float64 {
 	switch {
diff --git a/libgo/go/math/asinh.go b/libgo/go/math/asinh.go
index c1cad563c76..d6979463d65 100644
--- a/libgo/go/math/asinh.go
+++ b/libgo/go/math/asinh.go
@@ -33,8 +33,7 @@ package math
 // Asinh(x) calculates the inverse hyperbolic sine of x.
 //
 // Special cases are:
-//	Asinh(+Inf) = +Inf
-//	Asinh(-Inf) = -Inf
+//	Asinh(±Inf) = ±Inf
 //	Asinh(NaN) = NaN
 func Asinh(x float64) float64 {
 	const (
diff --git a/libgo/go/math/big/calibrate_test.go b/libgo/go/math/big/calibrate_test.go
index 1cd93b1052b..0950eeedbd2 100644
--- a/libgo/go/math/big/calibrate_test.go
+++ b/libgo/go/math/big/calibrate_test.go
@@ -22,14 +22,14 @@ import (
 var calibrate = flag.Bool("calibrate", false, "run calibration test")
 
 // measure returns the time to run f
-func measure(f func()) int64 {
+func measure(f func()) time.Duration {
 	const N = 100
-	start := time.Nanoseconds()
+	start := time.Now()
 	for i := N; i > 0; i-- {
 		f()
 	}
-	stop := time.Nanoseconds()
-	return (stop - start) / N
+	stop := time.Now()
+	return stop.Sub(start) / N
 }
 
 func computeThresholds() {
@@ -46,7 +46,7 @@ func computeThresholds() {
 	th1 := -1
 	th2 := -1
 
-	var deltaOld int64
+	var deltaOld time.Duration
 	for count := -1; count != 0; count-- {
 		// determine Tk, the work load execution time using Karatsuba multiplication
 		karatsubaThreshold = n // enable karatsuba
diff --git a/libgo/go/math/big/int_test.go b/libgo/go/math/big/int_test.go
index 163c662b0bb..aa7c1949549 100644
--- a/libgo/go/math/big/int_test.go
+++ b/libgo/go/math/big/int_test.go
@@ -1242,10 +1242,14 @@ func TestBitSet(t *testing.T) {
 		x.SetString(test.x, 0)
 		b := x.Bit(test.i)
 		if b != test.b {
-
-			t.Errorf("#%d want %v got %v", i, test.b, b)
+			t.Errorf("#%d got %v want %v", i, b, test.b)
 		}
 	}
+	z := NewInt(1)
+	z.SetBit(NewInt(0), 2, 1)
+	if z.Cmp(NewInt(4)) != 0 {
+		t.Errorf("destination leaked into result; got %s want 4", z)
+	}
 }
 
 func BenchmarkBitset(b *testing.B) {
diff --git a/libgo/go/math/big/nat.go b/libgo/go/math/big/nat.go
index eee8ee3f66c..680445dc9a7 100644
--- a/libgo/go/math/big/nat.go
+++ b/libgo/go/math/big/nat.go
@@ -21,7 +21,9 @@ package big
 import (
 	"errors"
 	"io"
+	"math"
 	"math/rand"
+	"sync"
 )
 
 // An unsigned integer x of the form
@@ -719,17 +721,17 @@ func (x nat) string(charset string) string {
 
 	// special cases
 	switch {
-	case b < 2 || b > 256:
+	case b < 2 || MaxBase < b:
 		panic("illegal base")
 	case len(x) == 0:
 		return string(charset[0])
 	}
 
 	// allocate buffer for conversion
-	i := x.bitLen()/log2(b) + 1 // +1: round up
+	i := int(float64(x.bitLen())/math.Log2(float64(b))) + 1 // off by one at most
 	s := make([]byte, i)
 
-	// special case: power of two bases can avoid divisions completely
+	// convert power of two and non power of two bases separately
 	if b == b&-b {
 		// shift is base-b digit size in bits
 		shift := uint(trailingZeroBits(b)) // shift > 0 because b >= 2
@@ -771,65 +773,209 @@ func (x nat) string(charset string) string {
 			w >>= shift
 			nbits -= shift
 		}
+	} else {
+		// determine "big base" as in 10^19 for 19 decimal digits in a 64 bit Word
+		bb := Word(1) // big base is b**ndigits
+		ndigits := 0  // number of base b digits
+		for max := Word(_M / b); bb <= max; bb *= b {
+			ndigits++ // maximize ndigits where bb = b**ndigits, bb <= _M
+		}
 
-		return string(s[i:])
+		// construct table of successive squares of bb*leafSize to use in subdivisions
+		table := divisors(len(x), b, ndigits, bb)
+
+		// preserve x, create local copy for use in divisions
+		q := nat(nil).set(x)
+
+		// convert q to string s in base b with index of MSD indicated by return value
+		i = q.convertWords(0, i, s, charset, b, ndigits, bb, table)
 	}
 
-	// general case: extract groups of digits by multiprecision division
+	return string(s[i:])
+}
 
-	// maximize ndigits where b**ndigits < 2^_W; bb (big base) is b**ndigits
-	bb := Word(1)
-	ndigits := 0
-	for max := Word(_M / b); bb <= max; bb *= b {
-		ndigits++
-	}
+// Convert words of q to base b digits in s directly using iterated nat/Word divison to extract
+// low-order Words and indirectly by recursive subdivision and nat/nat division by tabulated 
+// divisors. 
+//
+// The direct method processes n Words by n divW() calls, each of which visits every Word in the 
+// incrementally shortened q for a total of n + (n-1) + (n-2) ... + 2 + 1, or n(n+1)/2 divW()'s. 
+// Indirect conversion divides q by its approximate square root, yielding two parts, each half 
+// the size of q. Using the direct method on both halves means 2 * (n/2)(n/2 + 1)/2 divW()'s plus 
+// the expensive long div(). Asymptotically, the ratio is favorable at 1/2 the divW()'s, and is 
+// made better by splitting the subblocks recursively. Best is to split blocks until one more 
+// split would take longer (because of the nat/nat div()) than the twice as many divW()'s of the 
+// direct approach. This threshold is represented by leafSize. Benchmarking of leafSize in the 
+// range 2..64 shows that values of 8 and 16 work well, with a 4x speedup at medium lengths and 
+// ~30x for 20000 digits. Use nat_test.go's BenchmarkLeafSize tests to optimize leafSize for 
+// specfic hardware.
+//
+// lo and hi index character array s. conversion starts with the LSD at hi and moves down toward
+// the MSD, which will be at s[0] or s[1]. lo == 0 signals span includes the most significant word.
+//
+func (q nat) convertWords(lo, hi int, s []byte, charset string, b Word, ndigits int, bb Word, table []divisor) int {
+	// indirect conversion: split larger blocks to reduce quadratic expense of iterated nat/W division
+	if leafSize > 0 && len(q) > leafSize && table != nil {
+		var r nat
+		index := len(table) - 1
+		for len(q) > leafSize {
+			// find divisor close to sqrt(q) if possible, but in any case < q
+			maxLength := q.bitLen()     // ~= log2 q, or at of least largest possible q of this bit length
+			minLength := maxLength >> 1 // ~= log2 sqrt(q)
+			for index > 0 && table[index-1].nbits > minLength {
+				index-- // desired
+			}
+			if table[index].nbits >= maxLength && table[index].bbb.cmp(q) >= 0 {
+				index--
+				if index < 0 {
+					panic("internal inconsistency")
+				}
+			}
 
-	// preserve x, create local copy for use in repeated divisions
-	q := nat(nil).set(x)
+			// split q into the two digit number (q'*bbb + r) to form independent subblocks
+			q, r = q.div(r, q, table[index].bbb)
+
+			// convert subblocks and collect results in s[lo:partition] and s[partition:hi]
+			partition := hi - table[index].ndigits
+			r.convertWords(partition, hi, s, charset, b, ndigits, bb, table[0:index])
+			hi = partition // i.e., q.convertWords(lo, partition, s, charset, b, ndigits, bb, table[0:index+1])
+		}
+	} // having split any large blocks now process the remaining small block
+
+	// direct conversion: process smaller blocks monolithically to avoid overhead of nat/nat division
 	var r Word
-
-	// convert
-	if b == 10 { // hard-coding for 10 here speeds this up by 1.25x
+	if b == 10 { // hard-coding for 10 here speeds this up by 1.25x (allows mod as mul vs div)
 		for len(q) > 0 {
 			// extract least significant, base bb "digit"
-			q, r = q.divW(q, bb) // N.B. >82% of time is here. Optimize divW
-			if len(q) == 0 {
+			q, r = q.divW(q, bb)
+			if lo == 0 && len(q) == 0 {
 				// skip leading zeros in most-significant group of digits
 				for j := 0; j < ndigits && r != 0; j++ {
-					i--
-					s[i] = charset[r%10]
-					r /= 10
+					hi--
+					t := r / 10
+					s[hi] = charset[r-(t<<3+t<<1)] // 8*t + 2*t = 10*t; r - 10*int(r/10) = r mod 10
+					r = t
 				}
 			} else {
-				for j := 0; j < ndigits; j++ {
-					i--
-					s[i] = charset[r%10]
-					r /= 10
+				for j := 0; j < ndigits && hi > lo; j++ {
+					hi--
+					t := r / 10
+					s[hi] = charset[r-(t<<3+t<<1)] // 8*t + 2*t = 10*t; r - 10*int(r/10) = r mod 10
+					r = t
 				}
 			}
 		}
 	} else {
 		for len(q) > 0 {
 			// extract least significant group of digits
-			q, r = q.divW(q, bb) // N.B. >82% of time is here. Optimize divW
-			if len(q) == 0 {
+			q, r = q.divW(q, bb)
+			if lo == 0 && len(q) == 0 {
 				// skip leading zeros in most-significant group of digits
 				for j := 0; j < ndigits && r != 0; j++ {
-					i--
-					s[i] = charset[r%b]
-					r /= b
+					hi--
+					s[hi] = charset[r%b]
+					r = r / b
 				}
 			} else {
-				for j := 0; j < ndigits; j++ {
-					i--
-					s[i] = charset[r%b]
-					r /= b
+				for j := 0; j < ndigits && hi > lo; j++ {
+					hi--
+					s[hi] = charset[r%b]
+					r = r / b
 				}
 			}
 		}
 	}
 
-	return string(s[i:])
+	// prepend high-order zeroes when q has been normalized to a short number of Words.
+	// however, do not prepend zeroes when converting the most dignificant digits.
+	if lo != 0 { // if not MSD
+		zero := charset[0]
+		for hi > lo { // while need more leading zeroes
+			hi--
+			s[hi] = zero
+		}
+	}
+
+	// return index of most significant output digit in s[] (stored in lowest index)
+	return hi
+}
+
+// Split blocks greater than leafSize Words (or set to 0 to disable indirect conversion)
+// Benchmark and configure leafSize using: gotest -test.bench="Leaf"
+//   8 and 16 effective on 3.0 GHz Xeon "Clovertown" CPU (128 byte cache lines)
+//   8 and 16 effective on 2.66 GHz Core 2 Duo "Penryn" CPU
+var leafSize int = 8 // number of Word-size binary values treat as a monolithic block
+
+type divisor struct {
+	bbb     nat // divisor
+	nbits   int // bit length of divisor (discounting leading zeroes) ~= log2(bbb)
+	ndigits int // digit length of divisor in terms of output base digits
+}
+
+const maxCache = 64               // maximum number of divisors in a single table
+var cacheBase10 [maxCache]divisor // cached divisors for base 10
+var cacheLock sync.Mutex          // defense against concurrent table extensions
+
+// construct table of powers of bb*leafSize to use in subdivisions
+func divisors(m int, b Word, ndigits int, bb Word) []divisor {
+	// only build table when indirect conversion is enabled and x is large
+	if leafSize == 0 || m <= leafSize {
+		return nil
+	}
+
+	// determine k where (bb**leafSize)**(2**k) >= sqrt(x)
+	k := 1
+	for words := leafSize; words < m>>1 && k < maxCache; words <<= 1 {
+		k++
+	}
+
+	// create new table of divisors or extend and reuse existing table as appropriate
+	var cached bool
+	var table []divisor
+	switch b {
+	case 10:
+		table = cacheBase10[0:k] // reuse old table for this conversion
+		cached = true
+	default:
+		table = make([]divisor, k) // new table for this conversion
+	}
+
+	// extend table
+	if table[k-1].ndigits == 0 {
+		if cached {
+			cacheLock.Lock() // begin critical section
+		}
+
+		var i int
+		var larger nat
+		for i < k && table[i].ndigits != 0 { // skip existing entries
+			i++
+		}
+		for ; i < k; i++ { // add new entries
+			if i == 0 {
+				table[i].bbb = nat(nil).expWW(bb, Word(leafSize))
+				table[i].ndigits = ndigits * leafSize
+			} else {
+				table[i].bbb = nat(nil).mul(table[i-1].bbb, table[i-1].bbb)
+				table[i].ndigits = 2 * table[i-1].ndigits
+			}
+
+			// optimization: exploit aggregated extra bits in macro blocks
+			larger = nat(nil).set(table[i].bbb)
+			for mulAddVWW(larger, larger, b, 0) == 0 {
+				table[i].bbb = table[i].bbb.set(larger)
+				table[i].ndigits++
+			}
+
+			table[i].nbits = table[i].bbb.bitLen()
+		}
+
+		if cached {
+			cacheLock.Unlock() // end critical section
+		}
+	}
+
+	return table
 }
 
 const deBruijn32 = 0x077CB531
@@ -919,9 +1065,11 @@ func (z nat) setBit(x nat, i uint, b uint) nat {
 		return z.norm()
 	case 1:
 		if j >= n {
-			n = j + 1
+			z = z.make(j + 1)
+			z[n:].clear()
+		} else {
+			z = z.make(n)
 		}
-		z = z.make(n)
 		copy(z, x)
 		z[j] |= m
 		// no need to normalize
@@ -1140,7 +1288,12 @@ func (z nat) expNN(x, y, m nat) nat {
 		}
 	}
 
-	return z
+	return z.norm()
+}
+
+// calculate x**y for Word arguments y and y
+func (z nat) expWW(x, y Word) nat {
+	return z.expNN(nat(nil).setWord(x), nat(nil).setWord(y), nil)
 }
 
 // probablyPrime performs reps Miller-Rabin tests to check whether n is prime.
diff --git a/libgo/go/math/big/nat_test.go b/libgo/go/math/big/nat_test.go
index b208646f2f2..e3c6552d9fb 100644
--- a/libgo/go/math/big/nat_test.go
+++ b/libgo/go/math/big/nat_test.go
@@ -370,86 +370,34 @@ func BenchmarkScanPi(b *testing.B) {
 	}
 }
 
-const (
-	// 314**271
-	// base  2: 2249 digits
-	// base  8:  751 digits
-	// base 10:  678 digits
-	// base 16:  563 digits
-	shortBase     = 314
-	shortExponent = 271
+func BenchmarkScan10Base2(b *testing.B)     { ScanHelper(b, 2, 10, 10) }
+func BenchmarkScan100Base2(b *testing.B)    { ScanHelper(b, 2, 10, 100) }
+func BenchmarkScan1000Base2(b *testing.B)   { ScanHelper(b, 2, 10, 1000) }
+func BenchmarkScan10000Base2(b *testing.B)  { ScanHelper(b, 2, 10, 10000) }
+func BenchmarkScan100000Base2(b *testing.B) { ScanHelper(b, 2, 10, 100000) }
 
-	// 3141**2178
-	// base  2: 31577 digits
-	// base  8: 10527 digits
-	// base 10:  9507 digits
-	// base 16:  7895 digits
-	mediumBase     = 3141
-	mediumExponent = 2718
+func BenchmarkScan10Base8(b *testing.B)     { ScanHelper(b, 8, 10, 10) }
+func BenchmarkScan100Base8(b *testing.B)    { ScanHelper(b, 8, 10, 100) }
+func BenchmarkScan1000Base8(b *testing.B)   { ScanHelper(b, 8, 10, 1000) }
+func BenchmarkScan10000Base8(b *testing.B)  { ScanHelper(b, 8, 10, 10000) }
+func BenchmarkScan100000Base8(b *testing.B) { ScanHelper(b, 8, 10, 100000) }
 
-	// 3141**2178
-	// base  2: 406078 digits
-	// base  8: 135360 digits
-	// base 10: 122243 digits
-	// base 16: 101521 digits
-	longBase     = 31415
-	longExponent = 27182
-)
+func BenchmarkScan10Base10(b *testing.B)     { ScanHelper(b, 10, 10, 10) }
+func BenchmarkScan100Base10(b *testing.B)    { ScanHelper(b, 10, 10, 100) }
+func BenchmarkScan1000Base10(b *testing.B)   { ScanHelper(b, 10, 10, 1000) }
+func BenchmarkScan10000Base10(b *testing.B)  { ScanHelper(b, 10, 10, 10000) }
+func BenchmarkScan100000Base10(b *testing.B) { ScanHelper(b, 10, 10, 100000) }
 
-func BenchmarkScanShort2(b *testing.B) {
-	ScanHelper(b, 2, shortBase, shortExponent)
-}
+func BenchmarkScan10Base16(b *testing.B)     { ScanHelper(b, 16, 10, 10) }
+func BenchmarkScan100Base16(b *testing.B)    { ScanHelper(b, 16, 10, 100) }
+func BenchmarkScan1000Base16(b *testing.B)   { ScanHelper(b, 16, 10, 1000) }
+func BenchmarkScan10000Base16(b *testing.B)  { ScanHelper(b, 16, 10, 10000) }
+func BenchmarkScan100000Base16(b *testing.B) { ScanHelper(b, 16, 10, 100000) }
 
-func BenchmarkScanShort8(b *testing.B) {
-	ScanHelper(b, 8, shortBase, shortExponent)
-}
-
-func BenchmarkScanSort10(b *testing.B) {
-	ScanHelper(b, 10, shortBase, shortExponent)
-}
-
-func BenchmarkScanShort16(b *testing.B) {
-	ScanHelper(b, 16, shortBase, shortExponent)
-}
-
-func BenchmarkScanMedium2(b *testing.B) {
-	ScanHelper(b, 2, mediumBase, mediumExponent)
-}
-
-func BenchmarkScanMedium8(b *testing.B) {
-	ScanHelper(b, 8, mediumBase, mediumExponent)
-}
-
-func BenchmarkScanMedium10(b *testing.B) {
-	ScanHelper(b, 10, mediumBase, mediumExponent)
-}
-
-func BenchmarkScanMedium16(b *testing.B) {
-	ScanHelper(b, 16, mediumBase, mediumExponent)
-}
-
-func BenchmarkScanLong2(b *testing.B) {
-	ScanHelper(b, 2, longBase, longExponent)
-}
-
-func BenchmarkScanLong8(b *testing.B) {
-	ScanHelper(b, 8, longBase, longExponent)
-}
-
-func BenchmarkScanLong10(b *testing.B) {
-	ScanHelper(b, 10, longBase, longExponent)
-}
-
-func BenchmarkScanLong16(b *testing.B) {
-	ScanHelper(b, 16, longBase, longExponent)
-}
-
-func ScanHelper(b *testing.B, base int, xv, yv Word) {
+func ScanHelper(b *testing.B, base int, x, y Word) {
 	b.StopTimer()
-	var x, y, z nat
-	x = x.setWord(xv)
-	y = y.setWord(yv)
-	z = z.expNN(x, y, nil)
+	var z nat
+	z = z.expWW(x, y)
 
 	var s string
 	s = z.string(lowercaseDigits[0:base])
@@ -459,68 +407,112 @@ func ScanHelper(b *testing.B, base int, xv, yv Word) {
 	b.StartTimer()
 
 	for i := 0; i < b.N; i++ {
-		x.scan(strings.NewReader(s), base)
+		z.scan(strings.NewReader(s), base)
 	}
 }
 
-func BenchmarkStringShort2(b *testing.B) {
-	StringHelper(b, 2, shortBase, shortExponent)
-}
+func BenchmarkString10Base2(b *testing.B)     { StringHelper(b, 2, 10, 10) }
+func BenchmarkString100Base2(b *testing.B)    { StringHelper(b, 2, 10, 100) }
+func BenchmarkString1000Base2(b *testing.B)   { StringHelper(b, 2, 10, 1000) }
+func BenchmarkString10000Base2(b *testing.B)  { StringHelper(b, 2, 10, 10000) }
+func BenchmarkString100000Base2(b *testing.B) { StringHelper(b, 2, 10, 100000) }
 
-func BenchmarkStringShort8(b *testing.B) {
-	StringHelper(b, 8, shortBase, shortExponent)
-}
+func BenchmarkString10Base8(b *testing.B)     { StringHelper(b, 8, 10, 10) }
+func BenchmarkString100Base8(b *testing.B)    { StringHelper(b, 8, 10, 100) }
+func BenchmarkString1000Base8(b *testing.B)   { StringHelper(b, 8, 10, 1000) }
+func BenchmarkString10000Base8(b *testing.B)  { StringHelper(b, 8, 10, 10000) }
+func BenchmarkString100000Base8(b *testing.B) { StringHelper(b, 8, 10, 100000) }
 
-func BenchmarkStringShort10(b *testing.B) {
-	StringHelper(b, 10, shortBase, shortExponent)
-}
+func BenchmarkString10Base10(b *testing.B)     { StringHelper(b, 10, 10, 10) }
+func BenchmarkString100Base10(b *testing.B)    { StringHelper(b, 10, 10, 100) }
+func BenchmarkString1000Base10(b *testing.B)   { StringHelper(b, 10, 10, 1000) }
+func BenchmarkString10000Base10(b *testing.B)  { StringHelper(b, 10, 10, 10000) }
+func BenchmarkString100000Base10(b *testing.B) { StringHelper(b, 10, 10, 100000) }
 
-func BenchmarkStringShort16(b *testing.B) {
-	StringHelper(b, 16, shortBase, shortExponent)
-}
+func BenchmarkString10Base16(b *testing.B)     { StringHelper(b, 16, 10, 10) }
+func BenchmarkString100Base16(b *testing.B)    { StringHelper(b, 16, 10, 100) }
+func BenchmarkString1000Base16(b *testing.B)   { StringHelper(b, 16, 10, 1000) }
+func BenchmarkString10000Base16(b *testing.B)  { StringHelper(b, 16, 10, 10000) }
+func BenchmarkString100000Base16(b *testing.B) { StringHelper(b, 16, 10, 100000) }
 
-func BenchmarkStringMedium2(b *testing.B) {
-	StringHelper(b, 2, mediumBase, mediumExponent)
-}
-
-func BenchmarkStringMedium8(b *testing.B) {
-	StringHelper(b, 8, mediumBase, mediumExponent)
-}
-
-func BenchmarkStringMedium10(b *testing.B) {
-	StringHelper(b, 10, mediumBase, mediumExponent)
-}
-
-func BenchmarkStringMedium16(b *testing.B) {
-	StringHelper(b, 16, mediumBase, mediumExponent)
-}
-
-func BenchmarkStringLong2(b *testing.B) {
-	StringHelper(b, 2, longBase, longExponent)
-}
-
-func BenchmarkStringLong8(b *testing.B) {
-	StringHelper(b, 8, longBase, longExponent)
-}
-
-func BenchmarkStringLong10(b *testing.B) {
-	StringHelper(b, 10, longBase, longExponent)
-}
-
-func BenchmarkStringLong16(b *testing.B) {
-	StringHelper(b, 16, longBase, longExponent)
-}
-
-func StringHelper(b *testing.B, base int, xv, yv Word) {
+func StringHelper(b *testing.B, base int, x, y Word) {
 	b.StopTimer()
-	var x, y, z nat
-	x = x.setWord(xv)
-	y = y.setWord(yv)
-	z = z.expNN(x, y, nil)
+	var z nat
+	z = z.expWW(x, y)
+	z.string(lowercaseDigits[0:base]) // warm divisor cache
 	b.StartTimer()
 
 	for i := 0; i < b.N; i++ {
-		z.string(lowercaseDigits[0:base])
+		_ = z.string(lowercaseDigits[0:base])
+	}
+}
+
+func BenchmarkLeafSize0(b *testing.B)  { LeafSizeHelper(b, 10, 0) } // test without splitting
+func BenchmarkLeafSize1(b *testing.B)  { LeafSizeHelper(b, 10, 1) }
+func BenchmarkLeafSize2(b *testing.B)  { LeafSizeHelper(b, 10, 2) }
+func BenchmarkLeafSize3(b *testing.B)  { LeafSizeHelper(b, 10, 3) }
+func BenchmarkLeafSize4(b *testing.B)  { LeafSizeHelper(b, 10, 4) }
+func BenchmarkLeafSize5(b *testing.B)  { LeafSizeHelper(b, 10, 5) }
+func BenchmarkLeafSize6(b *testing.B)  { LeafSizeHelper(b, 10, 6) }
+func BenchmarkLeafSize7(b *testing.B)  { LeafSizeHelper(b, 10, 7) }
+func BenchmarkLeafSize8(b *testing.B)  { LeafSizeHelper(b, 10, 8) }
+func BenchmarkLeafSize9(b *testing.B)  { LeafSizeHelper(b, 10, 9) }
+func BenchmarkLeafSize10(b *testing.B) { LeafSizeHelper(b, 10, 10) }
+func BenchmarkLeafSize11(b *testing.B) { LeafSizeHelper(b, 10, 11) }
+func BenchmarkLeafSize12(b *testing.B) { LeafSizeHelper(b, 10, 12) }
+func BenchmarkLeafSize13(b *testing.B) { LeafSizeHelper(b, 10, 13) }
+func BenchmarkLeafSize14(b *testing.B) { LeafSizeHelper(b, 10, 14) }
+func BenchmarkLeafSize15(b *testing.B) { LeafSizeHelper(b, 10, 15) }
+func BenchmarkLeafSize16(b *testing.B) { LeafSizeHelper(b, 10, 16) }
+func BenchmarkLeafSize32(b *testing.B) { LeafSizeHelper(b, 10, 32) } // try some large lengths 
+func BenchmarkLeafSize64(b *testing.B) { LeafSizeHelper(b, 10, 64) }
+
+func LeafSizeHelper(b *testing.B, base Word, size int) {
+	b.StopTimer()
+	originalLeafSize := leafSize
+	resetTable(cacheBase10[:])
+	leafSize = size
+	b.StartTimer()
+
+	for d := 1; d <= 10000; d *= 10 {
+		b.StopTimer()
+		var z nat
+		z = z.expWW(base, Word(d))            // build target number
+		_ = z.string(lowercaseDigits[0:base]) // warm divisor cache
+		b.StartTimer()
+
+		for i := 0; i < b.N; i++ {
+			_ = z.string(lowercaseDigits[0:base])
+		}
+	}
+
+	b.StopTimer()
+	resetTable(cacheBase10[:])
+	leafSize = originalLeafSize
+	b.StartTimer()
+}
+
+func resetTable(table []divisor) {
+	if table != nil && table[0].bbb != nil {
+		for i := 0; i < len(table); i++ {
+			table[i].bbb = nil
+			table[i].nbits = 0
+			table[i].ndigits = 0
+		}
+	}
+}
+
+func TestStringPowers(t *testing.T) {
+	var b, p Word
+	for b = 2; b <= 16; b++ {
+		for p = 0; p <= 512; p++ {
+			x := nat(nil).expWW(b, p)
+			xs := x.string(lowercaseDigits[0:b])
+			xs2 := toString(x, lowercaseDigits[0:b])
+			if xs != xs2 {
+				t.Errorf("failed at %d ** %d in base %d: %s != %s", b, p, b, xs, xs2)
+			}
+		}
 	}
 }
 
diff --git a/libgo/go/math/cbrt.go b/libgo/go/math/cbrt.go
index d2b7e910b84..09edc0eae88 100644
--- a/libgo/go/math/cbrt.go
+++ b/libgo/go/math/cbrt.go
@@ -45,22 +45,21 @@ func Cbrt(x float64) float64 {
 		x = -x
 		sign = true
 	}
-	// Reduce argument
-	f, e := Frexp(x)
+	// Reduce argument and estimate cube root
+	f, e := Frexp(x) // 0.5 <= f < 1.0
 	m := e % 3
 	if m > 0 {
 		m -= 3
 		e -= m // e is multiple of 3
 	}
-	f = Ldexp(f, m) // 0.125 <= f < 1.0
-
-	// Estimate cube root
 	switch m {
 	case 0: // 0.5 <= f < 1.0
 		f = A1*f + A2 - A3/(A4+f)
-	case -1: // 0.25 <= f < 0.5
+	case -1:
+		f *= 0.5 // 0.25 <= f < 0.5
 		f = B1*f + B2 - B3/(B4+f)
-	default: // 0.125 <= f < 0.25
+	default: // m == -2
+		f *= 0.25 // 0.125 <= f < 0.25
 		f = C1*f + C2 - C3/(C4+f)
 	}
 	y := Ldexp(f, e/3) // e/3 = exponent of cube root
diff --git a/libgo/go/math/floor.go b/libgo/go/math/floor.go
index babbf645f5c..8de4d7e2ce6 100644
--- a/libgo/go/math/floor.go
+++ b/libgo/go/math/floor.go
@@ -7,8 +7,7 @@ package math
 // Floor returns the greatest integer value less than or equal to x.
 //
 // Special cases are:
-//	Floor(+Inf) = +Inf
-//	Floor(-Inf) = -Inf
+//	Floor(±Inf) = ±Inf
 //	Floor(NaN) = NaN
 func Floor(x float64) float64 {
 	// TODO(rsc): Remove manual inlining of IsNaN, IsInf
@@ -30,16 +29,14 @@ func Floor(x float64) float64 {
 // Ceil returns the least integer value greater than or equal to x.
 //
 // Special cases are:
-//	Ceil(+Inf) = +Inf
-//	Ceil(-Inf) = -Inf
+//	Ceil(±Inf) = ±Inf
 //	Ceil(NaN) = NaN
 func Ceil(x float64) float64 { return -Floor(-x) }
 
 // Trunc returns the integer value of x.
 //
 // Special cases are:
-//	Trunc(+Inf) = +Inf
-//	Trunc(-Inf) = -Inf
+//	Trunc(±Inf) = ±Inf
 //	Trunc(NaN) = NaN
 func Trunc(x float64) float64 {
 	// TODO(rsc): Remove manual inlining of IsNaN, IsInf
diff --git a/libgo/go/math/gamma.go b/libgo/go/math/gamma.go
index ae2c0c418ab..7365d8e7754 100644
--- a/libgo/go/math/gamma.go
+++ b/libgo/go/math/gamma.go
@@ -113,8 +113,7 @@ func stirling(x float64) float64 {
 // Gamma(x) returns the Gamma function of x.
 //
 // Special cases are:
-//	Gamma(Inf) = Inf
-//	Gamma(-Inf) = -Inf
+//	Gamma(±Inf) = ±Inf
 //	Gamma(NaN) = NaN
 // Large values overflow to +Inf.
 // Negative integer values equal ±Inf.
diff --git a/libgo/go/math/log1p.go b/libgo/go/math/log1p.go
index c25d73b6641..e8914a1d053 100644
--- a/libgo/go/math/log1p.go
+++ b/libgo/go/math/log1p.go
@@ -44,7 +44,7 @@ package math
 //                      2      4      6      8      10      12      14
 //          R(z) ~ Lp1*s +Lp2*s +Lp3*s +Lp4*s +Lp5*s  +Lp6*s  +Lp7*s
 //      (the values of Lp1 to Lp7 are listed in the program)
-//      a-0.2929nd
+//      and
 //          |      2          14          |     -58.45
 //          | Lp1*s +...+Lp7*s    -  R(z) | <= 2
 //          |                             |
@@ -88,6 +88,7 @@ package math
 //
 // Special cases are:
 //	Log1p(+Inf) = +Inf
+//	Log1p(±0) = ±0
 //	Log1p(-1) = -Inf
 //	Log1p(x < -1) = NaN
 //	Log1p(NaN) = NaN
diff --git a/libgo/go/math/modf.go b/libgo/go/math/modf.go
index 315174b7014..34889e0c0af 100644
--- a/libgo/go/math/modf.go
+++ b/libgo/go/math/modf.go
@@ -8,8 +8,7 @@ package math
 // that sum to f.  Both values have the same sign as f.
 //
 // Special cases are:
-//	Modf(+Inf) = +Inf, NaN
-//	Modf(-Inf) = -Inf, NaN
+//	Modf(±Inf) = ±Inf, NaN
 //	Modf(NaN) = NaN, NaN
 func Modf(f float64) (int float64, frac float64) {
 	if f < 1 {
diff --git a/libgo/go/math/sincos.go b/libgo/go/math/sincos.go
index 4c1576bead1..f5412fd726f 100644
--- a/libgo/go/math/sincos.go
+++ b/libgo/go/math/sincos.go
@@ -4,10 +4,66 @@
 
 package math
 
+// Coefficients _sin[] and _cos[] are found in pkg/math/sin.go.
+
 // Sincos(x) returns Sin(x), Cos(x).
 //
 // Special conditions are:
-//	Sincos(+Inf) = NaN, NaN
-//	Sincos(-Inf) = NaN, NaN
+//	Sincos(±0) = ±0, 1
+//	Sincos(±Inf) = NaN, NaN
 //	Sincos(NaN) = NaN, NaN
-func Sincos(x float64) (sin, cos float64) { return Sin(x), Cos(x) }
+func Sincos(x float64) (sin, cos float64) {
+	const (
+		PI4A = 7.85398125648498535156E-1                             // 0x3fe921fb40000000, Pi/4 split into three parts
+		PI4B = 3.77489470793079817668E-8                             // 0x3e64442d00000000,
+		PI4C = 2.69515142907905952645E-15                            // 0x3ce8469898cc5170,
+		M4PI = 1.273239544735162542821171882678754627704620361328125 // 4/pi
+	)
+	// TODO(rsc): Remove manual inlining of IsNaN, IsInf
+	// when compiler does it for us
+	// special cases
+	switch {
+	case x == 0:
+		return x, 1 // return ±0.0, 1.0
+	case x != x || x < -MaxFloat64 || x > MaxFloat64: // IsNaN(x) || IsInf(x, 0):
+		return NaN(), NaN()
+	}
+
+	// make argument positive
+	sinSign, cosSign := false, false
+	if x < 0 {
+		x = -x
+		sinSign = true
+	}
+
+	j := int64(x * M4PI) // integer part of x/(Pi/4), as integer for tests on the phase angle
+	y := float64(j)      // integer part of x/(Pi/4), as float
+
+	if j&1 == 1 { // map zeros to origin
+		j += 1
+		y += 1
+	}
+	j &= 7     // octant modulo 2Pi radians (360 degrees)
+	if j > 3 { // reflect in x axis
+		j -= 4
+		sinSign, cosSign = !sinSign, !cosSign
+	}
+	if j > 1 {
+		cosSign = !cosSign
+	}
+
+	z := ((x - y*PI4A) - y*PI4B) - y*PI4C // Extended precision modular arithmetic
+	zz := z * z
+	cos = 1.0 - 0.5*zz + zz*zz*((((((_cos[0]*zz)+_cos[1])*zz+_cos[2])*zz+_cos[3])*zz+_cos[4])*zz+_cos[5])
+	sin = z + z*zz*((((((_sin[0]*zz)+_sin[1])*zz+_sin[2])*zz+_sin[3])*zz+_sin[4])*zz+_sin[5])
+	if j == 1 || j == 2 {
+		sin, cos = cos, sin
+	}
+	if cosSign {
+		cos = -cos
+	}
+	if sinSign {
+		sin = -sin
+	}
+	return
+}
diff --git a/libgo/go/net/dnsclient_unix.go b/libgo/go/net/dnsclient_unix.go
index bab5f2a9b6e..79a958e3cd0 100644
--- a/libgo/go/net/dnsclient_unix.go
+++ b/libgo/go/net/dnsclient_unix.go
@@ -29,7 +29,7 @@ func exchange(cfg *dnsConfig, c Conn, name string, qtype uint16) (*dnsMsg, error
 		return nil, &DNSError{Err: "name too long", Name: name}
 	}
 	out := new(dnsMsg)
-	out.id = uint16(rand.Int()) ^ uint16(time.Nanoseconds())
+	out.id = uint16(rand.Int()) ^ uint16(time.Now().UnixNano())
 	out.question = []dnsQuestion{
 		{name, qtype, dnsClassINET},
 	}
diff --git a/libgo/go/net/fd.go b/libgo/go/net/fd.go
index 70e04a21c0b..5318c51c9a2 100644
--- a/libgo/go/net/fd.go
+++ b/libgo/go/net/fd.go
@@ -171,7 +171,7 @@ func (s *pollServer) WakeFD(fd *netFD, mode int) {
 }
 
 func (s *pollServer) Now() int64 {
-	return time.Nanoseconds()
+	return time.Now().UnixNano()
 }
 
 func (s *pollServer) CheckDeadlines() {
diff --git a/libgo/go/net/fd_windows.go b/libgo/go/net/fd_windows.go
index 7a1602371e9..264b918c57d 100644
--- a/libgo/go/net/fd_windows.go
+++ b/libgo/go/net/fd_windows.go
@@ -172,11 +172,12 @@ 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 {
 		select {
 		case r = <-o.resultc:
-		case <-time.After(deadline_delta):
+		case <-time.After(time.Duration(deadline_delta) * time.Nanosecond):
 			s.canchan <- oi
 			<-o.errnoc
 			r = <-o.resultc
diff --git a/libgo/go/net/hosts.go b/libgo/go/net/hosts.go
index ddfb074ee8f..e6674ba3415 100644
--- a/libgo/go/net/hosts.go
+++ b/libgo/go/net/hosts.go
@@ -11,7 +11,7 @@ import (
 	"time"
 )
 
-const cacheMaxAge = int64(300) // 5 minutes.
+const cacheMaxAge = 5 * time.Minute
 
 // hostsPath points to the file with static IP/address entries.
 var hostsPath = "/etc/hosts"
@@ -21,14 +21,14 @@ var hosts struct {
 	sync.Mutex
 	byName map[string][]string
 	byAddr map[string][]string
-	time   int64
+	expire time.Time
 	path   string
 }
 
 func readHosts() {
-	now := time.Seconds()
+	now := time.Now()
 	hp := hostsPath
-	if len(hosts.byName) == 0 || hosts.time+cacheMaxAge <= now || hosts.path != hp {
+	if len(hosts.byName) == 0 || now.After(hosts.expire) || hosts.path != hp {
 		hs := make(map[string][]string)
 		is := make(map[string][]string)
 		var file *file
@@ -51,7 +51,7 @@ func readHosts() {
 			}
 		}
 		// Update the data cache.
-		hosts.time = time.Seconds()
+		hosts.expire = time.Now().Add(cacheMaxAge)
 		hosts.path = hp
 		hosts.byName = hs
 		hosts.byAddr = is
diff --git a/libgo/go/net/http/cgi/host_test.go b/libgo/go/net/http/cgi/host_test.go
index e6e85e8db3b..849cb008b76 100644
--- a/libgo/go/net/http/cgi/host_test.go
+++ b/libgo/go/net/http/cgi/host_test.go
@@ -365,7 +365,7 @@ func TestCopyError(t *testing.T) {
 
 	tries := 0
 	for tries < 15 && childRunning() {
-		time.Sleep(50e6 * int64(tries))
+		time.Sleep(50 * time.Millisecond * time.Duration(tries))
 		tries++
 	}
 	if childRunning() {
diff --git a/libgo/go/net/http/cookie.go b/libgo/go/net/http/cookie.go
index 69350143248..cad852242e2 100644
--- a/libgo/go/net/http/cookie.go
+++ b/libgo/go/net/http/cookie.go
@@ -115,7 +115,7 @@ func readSetCookies(h Header) []*Cookie {
 						break
 					}
 				}
-				c.Expires = *exptime
+				c.Expires = exptime.UTC()
 				continue
 			case "path":
 				c.Path = val
@@ -146,8 +146,8 @@ func (c *Cookie) String() string {
 	if len(c.Domain) > 0 {
 		fmt.Fprintf(&b, "; Domain=%s", sanitizeValue(c.Domain))
 	}
-	if len(c.Expires.Zone) > 0 {
-		fmt.Fprintf(&b, "; Expires=%s", c.Expires.Format(time.RFC1123))
+	if c.Expires.Unix() > 0 {
+		fmt.Fprintf(&b, "; Expires=%s", c.Expires.UTC().Format(time.RFC1123))
 	}
 	if c.MaxAge > 0 {
 		fmt.Fprintf(&b, "; Max-Age=%d", c.MaxAge)
diff --git a/libgo/go/net/http/cookie_test.go b/libgo/go/net/http/cookie_test.go
index 24adf202981..26bff93f643 100644
--- a/libgo/go/net/http/cookie_test.go
+++ b/libgo/go/net/http/cookie_test.go
@@ -123,7 +123,7 @@ var readSetCookiesTests = []struct {
 			Path:       "/",
 			Domain:     ".google.ch",
 			HttpOnly:   true,
-			Expires:    time.Time{Year: 2011, Month: 11, Day: 23, Hour: 1, Minute: 5, Second: 3, ZoneOffset: 0, Zone: "GMT"},
+			Expires:    time.Date(2011, 11, 23, 1, 5, 3, 0, time.UTC),
 			RawExpires: "Wed, 23-Nov-2011 01:05:03 GMT",
 			Raw:        "NID=99=YsDT5i3E-CXax-; expires=Wed, 23-Nov-2011 01:05:03 GMT; path=/; domain=.google.ch; HttpOnly",
 		}},
diff --git a/libgo/go/net/http/export_test.go b/libgo/go/net/http/export_test.go
index 3fe658641f8..13640ca85ee 100644
--- a/libgo/go/net/http/export_test.go
+++ b/libgo/go/net/http/export_test.go
@@ -7,6 +7,8 @@
 
 package http
 
+import "time"
+
 func (t *Transport) IdleConnKeysForTesting() (keys []string) {
 	keys = make([]string, 0)
 	t.lk.Lock()
@@ -33,8 +35,8 @@ func (t *Transport) IdleConnCountForTesting(cacheKey string) int {
 	return len(conns)
 }
 
-func NewTestTimeoutHandler(handler Handler, ch <-chan int64) Handler {
-	f := func() <-chan int64 {
+func NewTestTimeoutHandler(handler Handler, ch <-chan time.Time) Handler {
+	f := func() <-chan time.Time {
 		return ch
 	}
 	return &timeoutHandler{handler, f, ""}
diff --git a/libgo/go/net/http/fcgi/child.go b/libgo/go/net/http/fcgi/child.go
index 529440cbe92..c94b9a7b249 100644
--- a/libgo/go/net/http/fcgi/child.go
+++ b/libgo/go/net/http/fcgi/child.go
@@ -103,7 +103,7 @@ func (r *response) WriteHeader(code int) {
 	}
 
 	if r.header.Get("Date") == "" {
-		r.header.Set("Date", time.UTC().Format(http.TimeFormat))
+		r.header.Set("Date", time.Now().UTC().Format(http.TimeFormat))
 	}
 
 	fmt.Fprintf(r.w, "Status: %d %s\r\n", code, http.StatusText(code))
diff --git a/libgo/go/net/http/fs.go b/libgo/go/net/http/fs.go
index 5aadac17a23..70e7849f167 100644
--- a/libgo/go/net/http/fs.go
+++ b/libgo/go/net/http/fs.go
@@ -52,7 +52,7 @@ type FileSystem interface {
 // served by the FileServer implementation.
 type File interface {
 	Close() error
-	Stat() (*os.FileInfo, error)
+	Stat() (os.FileInfo, error)
 	Readdir(count int) ([]os.FileInfo, error)
 	Read([]byte) (int, error)
 	Seek(offset int64, whence int) (int64, error)
@@ -93,8 +93,8 @@ func dirList(w ResponseWriter, f File) {
 			break
 		}
 		for _, d := range dirs {
-			name := d.Name
-			if d.IsDirectory() {
+			name := d.Name()
+			if d.IsDir() {
 				name += "/"
 			}
 			// TODO htmlescape
@@ -135,7 +135,7 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec
 		// redirect to canonical path: / at end of directory url
 		// r.URL.Path always begins with /
 		url := r.URL.Path
-		if d.IsDirectory() {
+		if d.IsDir() {
 			if url[len(url)-1] != '/' {
 				localRedirect(w, r, path.Base(url)+"/")
 				return
@@ -148,14 +148,14 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec
 		}
 	}
 
-	if t, _ := time.Parse(TimeFormat, r.Header.Get("If-Modified-Since")); t != nil && d.Mtime_ns/1e9 <= t.Seconds() {
+	if t, err := time.Parse(TimeFormat, r.Header.Get("If-Modified-Since")); err == nil && !d.ModTime().After(t) {
 		w.WriteHeader(StatusNotModified)
 		return
 	}
-	w.Header().Set("Last-Modified", time.SecondsToUTC(d.Mtime_ns/1e9).Format(TimeFormat))
+	w.Header().Set("Last-Modified", d.ModTime().UTC().Format(TimeFormat))
 
 	// use contents of index.html for directory, if present
-	if d.IsDirectory() {
+	if d.IsDir() {
 		index := name + indexPage
 		ff, err := fs.Open(index)
 		if err == nil {
@@ -169,13 +169,13 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec
 		}
 	}
 
-	if d.IsDirectory() {
+	if d.IsDir() {
 		dirList(w, f)
 		return
 	}
 
 	// serve file
-	size := d.Size
+	size := d.Size()
 	code := StatusOK
 
 	// If Content-Type isn't set, use the file's extension to find it.
@@ -215,7 +215,7 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec
 		}
 		size = ra.length
 		code = StatusPartialContent
-		w.Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", ra.start, ra.start+ra.length-1, d.Size))
+		w.Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", ra.start, ra.start+ra.length-1, d.Size()))
 	}
 
 	w.Header().Set("Accept-Ranges", "bytes")
diff --git a/libgo/go/net/http/fs_test.go b/libgo/go/net/http/fs_test.go
index 6697189900e..976ee75c7dd 100644
--- a/libgo/go/net/http/fs_test.go
+++ b/libgo/go/net/http/fs_test.go
@@ -190,8 +190,8 @@ func TestDirJoin(t *testing.T) {
 		if err != nil {
 			t.Fatalf("stat of %s: %v", name, err)
 		}
-		if gfi.Ino != wfi.Ino {
-			t.Errorf("%s got different inode", name)
+		if !gfi.(*os.FileStat).SameFile(wfi.(*os.FileStat)) {
+			t.Errorf("%s got different file", name)
 		}
 	}
 	test(Dir("/etc/"), "/hosts")
diff --git a/libgo/go/net/http/httptest/server.go b/libgo/go/net/http/httptest/server.go
index f09e826d9c9..5b02e143d4a 100644
--- a/libgo/go/net/http/httptest/server.go
+++ b/libgo/go/net/http/httptest/server.go
@@ -7,14 +7,12 @@
 package httptest
 
 import (
-	"crypto/rand"
 	"crypto/tls"
 	"flag"
 	"fmt"
 	"net"
 	"net/http"
 	"os"
-	"time"
 )
 
 // A Server is an HTTP server listening on a system-chosen port on the
@@ -113,8 +111,6 @@ func (s *Server) StartTLS() {
 	}
 
 	s.TLS = &tls.Config{
-		Rand:         rand.Reader,
-		Time:         time.Seconds,
 		NextProtos:   []string{"http/1.1"},
 		Certificates: []tls.Certificate{cert},
 	}
diff --git a/libgo/go/net/http/httputil/reverseproxy.go b/libgo/go/net/http/httputil/reverseproxy.go
index bfcb3ca6b11..1dc83e7d032 100644
--- a/libgo/go/net/http/httputil/reverseproxy.go
+++ b/libgo/go/net/http/httputil/reverseproxy.go
@@ -31,11 +31,11 @@ type ReverseProxy struct {
 	// If nil, http.DefaultTransport is used.
 	Transport http.RoundTripper
 
-	// FlushInterval specifies the flush interval, in
-	// nanoseconds, to flush to the client while
-	// coping the response body.
+	// FlushInterval specifies the flush interval
+	// to flush to the client while copying the
+	// response body.
 	// If zero, no periodic flushing is done.
-	FlushInterval int64
+	FlushInterval time.Duration
 }
 
 func singleJoiningSlash(a, b string) string {
@@ -135,7 +135,7 @@ type writeFlusher interface {
 
 type maxLatencyWriter struct {
 	dst     writeFlusher
-	latency int64 // nanos
+	latency time.Duration
 
 	lk   sync.Mutex // protects init of done, as well Write + Flush
 	done chan bool
diff --git a/libgo/go/net/http/pprof/pprof.go b/libgo/go/net/http/pprof/pprof.go
index c0327a94824..2de147579d1 100644
--- a/libgo/go/net/http/pprof/pprof.go
+++ b/libgo/go/net/http/pprof/pprof.go
@@ -80,7 +80,7 @@ func Profile(w http.ResponseWriter, r *http.Request) {
 		fmt.Fprintf(w, "Could not enable CPU profiling: %s\n", err)
 		return
 	}
-	time.Sleep(sec * 1e9)
+	time.Sleep(time.Duration(sec) * time.Second)
 	pprof.StopCPUProfile()
 }
 
diff --git a/libgo/go/net/http/serve_test.go b/libgo/go/net/http/serve_test.go
index 97a0b139e39..670b5418fcd 100644
--- a/libgo/go/net/http/serve_test.go
+++ b/libgo/go/net/http/serve_test.go
@@ -266,19 +266,19 @@ func TestServerTimeouts(t *testing.T) {
 	}
 
 	// Slow client that should timeout.
-	t1 := time.Nanoseconds()
+	t1 := time.Now()
 	conn, err := net.Dial("tcp", addr.String())
 	if err != nil {
 		t.Fatalf("Dial: %v", err)
 	}
 	buf := make([]byte, 1)
 	n, err := conn.Read(buf)
-	latency := time.Nanoseconds() - t1
+	latency := time.Now().Sub(t1)
 	if n != 0 || err != io.EOF {
 		t.Errorf("Read = %v, %v, wanted %v, %v", n, err, 0, io.EOF)
 	}
-	if latency < second*0.20 /* fudge from 0.25 above */ {
-		t.Errorf("got EOF after %d ns, want >= %d", latency, second*0.20)
+	if latency < 200*time.Millisecond /* fudge from 0.25 above */ {
+		t.Errorf("got EOF after %s, want >= %s", latency, 200*time.Millisecond)
 	}
 
 	// Hit the HTTP server successfully again, verifying that the
@@ -760,7 +760,7 @@ func TestTimeoutHandler(t *testing.T) {
 		_, werr := w.Write([]byte("hi"))
 		writeErrors <- werr
 	})
-	timeout := make(chan int64, 1) // write to this to force timeouts
+	timeout := make(chan time.Time, 1) // write to this to force timeouts
 	ts := httptest.NewServer(NewTestTimeoutHandler(sayHi, timeout))
 	defer ts.Close()
 
@@ -782,7 +782,7 @@ func TestTimeoutHandler(t *testing.T) {
 	}
 
 	// Times out:
-	timeout <- 1
+	timeout <- time.Time{}
 	res, err = Get(ts.URL)
 	if err != nil {
 		t.Error(err)
diff --git a/libgo/go/net/http/server.go b/libgo/go/net/http/server.go
index 7221d2508bb..125f3f214bb 100644
--- a/libgo/go/net/http/server.go
+++ b/libgo/go/net/http/server.go
@@ -347,7 +347,7 @@ func (w *response) WriteHeader(code int) {
 	}
 
 	if _, ok := w.header["Date"]; !ok {
-		w.Header().Set("Date", time.UTC().Format(TimeFormat))
+		w.Header().Set("Date", time.Now().UTC().Format(TimeFormat))
 	}
 
 	te := w.header.Get("Transfer-Encoding")
@@ -467,7 +467,7 @@ func (w *response) Write(data []byte) (n int, err error) {
 		// determine the content type.  Accumulate the
 		// initial writes in w.conn.body.
 		// Cap m so that append won't allocate.
-		m := cap(w.conn.body) - len(w.conn.body)
+		m = cap(w.conn.body) - len(w.conn.body)
 		if m > len(data) {
 			m = len(data)
 		}
@@ -1013,8 +1013,8 @@ func (srv *Server) Serve(l net.Listener) error {
 //	package main
 //
 //	import (
-//		"http"
 //		"io"
+//		"net/http"
 //		"log"
 //	)
 //
@@ -1044,8 +1044,8 @@ func ListenAndServe(addr string, handler Handler) error {
 // A trivial example server is:
 //
 //	import (
-//		"http"
 //		"log"
+//		"net/http"
 //	)
 //
 //	func handler(w http.ResponseWriter, req *http.Request) {
@@ -1084,7 +1084,6 @@ func (s *Server) ListenAndServeTLS(certFile, keyFile string) error {
 	}
 	config := &tls.Config{
 		Rand:       rand.Reader,
-		Time:       time.Seconds,
 		NextProtos: []string{"http/1.1"},
 	}
 
@@ -1112,9 +1111,9 @@ func (s *Server) ListenAndServeTLS(certFile, keyFile string) error {
 // (If msg is empty, a suitable default message will be sent.)
 // After such a timeout, writes by h to its ResponseWriter will return
 // ErrHandlerTimeout.
-func TimeoutHandler(h Handler, ns int64, msg string) Handler {
-	f := func() <-chan int64 {
-		return time.After(ns)
+func TimeoutHandler(h Handler, dt time.Duration, msg string) Handler {
+	f := func() <-chan time.Time {
+		return time.After(dt)
 	}
 	return &timeoutHandler{h, f, msg}
 }
@@ -1125,7 +1124,7 @@ var ErrHandlerTimeout = errors.New("http: Handler timeout")
 
 type timeoutHandler struct {
 	handler Handler
-	timeout func() <-chan int64 // returns channel producing a timeout
+	timeout func() <-chan time.Time // returns channel producing a timeout
 	body    string
 }
 
diff --git a/libgo/go/net/http/sniff.go b/libgo/go/net/http/sniff.go
index 5707c7f057f..c1c78e2417d 100644
--- a/libgo/go/net/http/sniff.go
+++ b/libgo/go/net/http/sniff.go
@@ -48,23 +48,23 @@ type sniffSig interface {
 
 // Data matching the table in section 6.
 var sniffSignatures = []sniffSig{
-	htmlSig([]byte("<!DOCTYPE HTML")),
-	htmlSig([]byte("<HTML")),
-	htmlSig([]byte("<HEAD")),
-	htmlSig([]byte("<SCRIPT")),
-	htmlSig([]byte("<IFRAME")),
-	htmlSig([]byte("<H1")),
-	htmlSig([]byte("<DIV")),
-	htmlSig([]byte("<FONT")),
-	htmlSig([]byte("<TABLE")),
-	htmlSig([]byte("<A")),
-	htmlSig([]byte("<STYLE")),
-	htmlSig([]byte("<TITLE")),
-	htmlSig([]byte("<B")),
-	htmlSig([]byte("<BODY")),
-	htmlSig([]byte("<BR")),
-	htmlSig([]byte("<P")),
-	htmlSig([]byte("<!--")),
+	htmlSig("<!DOCTYPE HTML"),
+	htmlSig("<HTML"),
+	htmlSig("<HEAD"),
+	htmlSig("<SCRIPT"),
+	htmlSig("<IFRAME"),
+	htmlSig("<H1"),
+	htmlSig("<DIV"),
+	htmlSig("<FONT"),
+	htmlSig("<TABLE"),
+	htmlSig("<A"),
+	htmlSig("<STYLE"),
+	htmlSig("<TITLE"),
+	htmlSig("<B"),
+	htmlSig("<BODY"),
+	htmlSig("<BR"),
+	htmlSig("<P"),
+	htmlSig("<!--"),
 
 	&maskedSig{mask: []byte("\xFF\xFF\xFF\xFF\xFF"), pat: []byte("<?xml"), skipWS: true, ct: "text/xml; charset=utf-8"},
 
diff --git a/libgo/go/net/http/sniff_test.go b/libgo/go/net/http/sniff_test.go
index 86744eeb56b..6efa8ce1ca2 100644
--- a/libgo/go/net/http/sniff_test.go
+++ b/libgo/go/net/http/sniff_test.go
@@ -6,12 +6,14 @@ package http_test
 
 import (
 	"bytes"
+	"fmt"
 	"io"
 	"io/ioutil"
 	"log"
 	. "net/http"
 	"net/http/httptest"
 	"strconv"
+	"strings"
 	"testing"
 )
 
@@ -112,3 +114,24 @@ func TestContentTypeWithCopy(t *testing.T) {
 	}
 	resp.Body.Close()
 }
+
+func TestSniffWriteSize(t *testing.T) {
+	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+		size, _ := strconv.Atoi(r.FormValue("size"))
+		written, err := io.WriteString(w, strings.Repeat("a", size))
+		if err != nil {
+			t.Errorf("write of %d bytes: %v", size, err)
+			return
+		}
+		if written != size {
+			t.Errorf("write of %d bytes wrote %d bytes", size, written)
+		}
+	}))
+	defer ts.Close()
+	for _, size := range []int{0, 1, 200, 600, 999, 1000, 1023, 1024, 512 << 10, 1 << 20} {
+		_, err := Get(fmt.Sprintf("%s/?size=%d", ts.URL, size))
+		if err != nil {
+			t.Fatalf("size %d: %v", size, err)
+		}
+	}
+}
diff --git a/libgo/go/net/http/transport_test.go b/libgo/go/net/http/transport_test.go
index 77297972449..6f50f6f2767 100644
--- a/libgo/go/net/http/transport_test.go
+++ b/libgo/go/net/http/transport_test.go
@@ -263,7 +263,7 @@ func TestTransportServerClosingUnexpectedly(t *testing.T) {
 				t.Fatalf(format, arg...)
 			}
 			t.Logf("retrying shortly after expected error: "+format, arg...)
-			time.Sleep(1e9 / int64(retries))
+			time.Sleep(time.Second / time.Duration(retries))
 		}
 		for retries >= 0 {
 			retries--
diff --git a/libgo/go/net/mail/message.go b/libgo/go/net/mail/message.go
index 95246b2fa1d..e1afa32062f 100644
--- a/libgo/go/net/mail/message.go
+++ b/libgo/go/net/mail/message.go
@@ -89,14 +89,14 @@ func init() {
 	}
 }
 
-func parseDate(date string) (*time.Time, error) {
+func parseDate(date string) (time.Time, error) {
 	for _, layout := range dateLayouts {
 		t, err := time.Parse(layout, date)
 		if err == nil {
 			return t, nil
 		}
 	}
-	return nil, errors.New("mail: header could not be parsed")
+	return time.Time{}, errors.New("mail: header could not be parsed")
 }
 
 // A Header represents the key-value pairs in a mail message header.
@@ -111,10 +111,10 @@ func (h Header) Get(key string) string {
 var ErrHeaderNotPresent = errors.New("mail: header not in message")
 
 // Date parses the Date header field.
-func (h Header) Date() (*time.Time, error) {
+func (h Header) Date() (time.Time, error) {
 	hdr := h.Get("Date")
 	if hdr == "" {
-		return nil, ErrHeaderNotPresent
+		return time.Time{}, ErrHeaderNotPresent
 	}
 	return parseDate(hdr)
 }
@@ -185,7 +185,7 @@ func (a *Address) String() string {
 type addrParser []byte
 
 func newAddrParser(s string) *addrParser {
-	p := addrParser([]byte(s))
+	p := addrParser(s)
 	return &p
 }
 
diff --git a/libgo/go/net/mail/message_test.go b/libgo/go/net/mail/message_test.go
index 5653647b8cc..1f71cc480af 100644
--- a/libgo/go/net/mail/message_test.go
+++ b/libgo/go/net/mail/message_test.go
@@ -82,34 +82,18 @@ func headerEq(a, b Header) bool {
 func TestDateParsing(t *testing.T) {
 	tests := []struct {
 		dateStr string
-		exp     *time.Time
+		exp     time.Time
 	}{
 		// RFC 5322, Appendix A.1.1
 		{
 			"Fri, 21 Nov 1997 09:55:06 -0600",
-			&time.Time{
-				Year:       1997,
-				Month:      11,
-				Day:        21,
-				Hour:       9,
-				Minute:     55,
-				Second:     6,
-				ZoneOffset: -6 * 60 * 60,
-			},
+			time.Date(1997, 11, 21, 9, 55, 6, 0, time.FixedZone("", -6*60*60)),
 		},
 		// RFC5322, Appendix A.6.2
 		// Obsolete date.
 		{
 			"21 Nov 97 09:55:06 GMT",
-			&time.Time{
-				Year:   1997,
-				Month:  11,
-				Day:    21,
-				Hour:   9,
-				Minute: 55,
-				Second: 6,
-				Zone:   "GMT",
-			},
+			time.Date(1997, 11, 21, 9, 55, 6, 0, time.FixedZone("GMT", 0)),
 		},
 	}
 	for _, test := range tests {
diff --git a/libgo/go/net/timeout_test.go b/libgo/go/net/timeout_test.go
index 3c884ca7cfe..f6e5238c1b1 100644
--- a/libgo/go/net/timeout_test.go
+++ b/libgo/go/net/timeout_test.go
@@ -17,7 +17,7 @@ func testTimeout(t *testing.T, network, addr string, readFrom bool) {
 		return
 	}
 	defer fd.Close()
-	t0 := time.Nanoseconds()
+	t0 := time.Now()
 	fd.SetReadTimeout(1e8) // 100ms
 	var b [100]byte
 	var n int
@@ -27,7 +27,7 @@ func testTimeout(t *testing.T, network, addr string, readFrom bool) {
 	} else {
 		n, err1 = fd.Read(b[0:])
 	}
-	t1 := time.Nanoseconds()
+	t1 := time.Now()
 	what := "Read"
 	if readFrom {
 		what = "ReadFrom"
@@ -35,8 +35,8 @@ func testTimeout(t *testing.T, network, addr string, readFrom bool) {
 	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 t1-t0 < 0.5e8 || t1-t0 > 1.5e8 {
-		t.Errorf("fd.%s on %s %s took %f seconds, expected 0.1", what, network, addr, float64(t1-t0)/1e9)
+	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)
 	}
 }
 
diff --git a/libgo/go/old/netchan/common.go b/libgo/go/old/netchan/common.go
index dfd1fd03427..03fa8ff6c41 100644
--- a/libgo/go/old/netchan/common.go
+++ b/libgo/go/old/netchan/common.go
@@ -129,8 +129,8 @@ func (ed *encDec) encode(hdr *header, payloadType int, payload interface{}) erro
 }
 
 // See the comment for Exporter.Drain.
-func (cs *clientSet) drain(timeout int64) error {
-	startTime := time.Nanoseconds()
+func (cs *clientSet) drain(timeout time.Duration) error {
+	deadline := time.Now().Add(timeout)
 	for {
 		pending := false
 		cs.mu.Lock()
@@ -152,7 +152,7 @@ func (cs *clientSet) drain(timeout int64) error {
 		if !pending {
 			break
 		}
-		if timeout > 0 && time.Nanoseconds()-startTime >= timeout {
+		if timeout > 0 && time.Now().After(deadline) {
 			return errors.New("timeout")
 		}
 		time.Sleep(100 * 1e6) // 100 milliseconds
@@ -161,8 +161,8 @@ func (cs *clientSet) drain(timeout int64) error {
 }
 
 // See the comment for Exporter.Sync.
-func (cs *clientSet) sync(timeout int64) error {
-	startTime := time.Nanoseconds()
+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)
 	for client := range cs.clients {
@@ -185,7 +185,7 @@ func (cs *clientSet) sync(timeout int64) error {
 		if !pending {
 			break
 		}
-		if timeout > 0 && time.Nanoseconds()-startTime >= timeout {
+		if timeout > 0 && time.Now().After(deadline) {
 			return errors.New("timeout")
 		}
 		time.Sleep(100 * 1e6) // 100 milliseconds
diff --git a/libgo/go/old/netchan/export.go b/libgo/go/old/netchan/export.go
index d698dd53a90..d94c4b16b21 100644
--- a/libgo/go/old/netchan/export.go
+++ b/libgo/go/old/netchan/export.go
@@ -29,6 +29,7 @@ import (
 	"reflect"
 	"strconv"
 	"sync"
+	"time"
 )
 
 // Export
@@ -322,9 +323,9 @@ func (exp *Exporter) delClient(client *expClient) {
 // those not yet sent to any client and possibly including those sent while
 // Drain was executing, have been received by the importer.  In short, it
 // waits until all the exporter's messages have been received by a client.
-// If the timeout (measured in nanoseconds) is positive and Drain takes
-// longer than that to complete, an error is returned.
-func (exp *Exporter) Drain(timeout int64) error {
+// If the timeout is positive and Drain takes longer than that to complete,
+// an error is returned.
+func (exp *Exporter) Drain(timeout time.Duration) error {
 	// This wrapper function is here so the method's comment will appear in godoc.
 	return exp.clientSet.drain(timeout)
 }
@@ -332,10 +333,9 @@ func (exp *Exporter) Drain(timeout int64) error {
 // Sync waits until all clients of the exporter have received the messages
 // that were sent at the time Sync was invoked.  Unlike Drain, it does not
 // wait for messages sent while it is running or messages that have not been
-// dispatched to any client.  If the timeout (measured in nanoseconds) is
-// positive and Sync takes longer than that to complete, an error is
-// returned.
-func (exp *Exporter) Sync(timeout int64) error {
+// dispatched to any client.  If the timeout is positive and Sync takes longer
+// than that to complete, an error is returned.
+func (exp *Exporter) Sync(timeout time.Duration) error {
 	// This wrapper function is here so the method's comment will appear in godoc.
 	return exp.clientSet.sync(timeout)
 }
diff --git a/libgo/go/old/netchan/import.go b/libgo/go/old/netchan/import.go
index 7243672ecd3..a6da8210b99 100644
--- a/libgo/go/old/netchan/import.go
+++ b/libgo/go/old/netchan/import.go
@@ -276,9 +276,9 @@ func (imp *Importer) unackedCount() int64 {
 // If the timeout (measured in nanoseconds) is positive and Drain takes
 // longer than that to complete, an error is returned.
 func (imp *Importer) Drain(timeout int64) error {
-	startTime := time.Nanoseconds()
+	deadline := time.Now().Add(time.Duration(timeout))
 	for imp.unackedCount() > 0 {
-		if timeout > 0 && time.Nanoseconds()-startTime >= timeout {
+		if timeout > 0 && time.Now().After(deadline) {
 			return errors.New("timeout")
 		}
 		time.Sleep(100 * 1e6)
diff --git a/libgo/go/os/exec/lp_unix.go b/libgo/go/os/exec/lp_unix.go
index d234641acc4..9665ea8f413 100644
--- a/libgo/go/os/exec/lp_unix.go
+++ b/libgo/go/os/exec/lp_unix.go
@@ -20,7 +20,7 @@ func findExecutable(file string) error {
 	if err != nil {
 		return err
 	}
-	if d.IsRegular() && d.Permission()&0111 != 0 {
+	if m := d.Mode(); !m.IsDir() && m&0111 != 0 {
 		return nil
 	}
 	return os.EPERM
diff --git a/libgo/go/os/exec/lp_windows.go b/libgo/go/os/exec/lp_windows.go
index db326236ee8..ef5bd921668 100644
--- a/libgo/go/os/exec/lp_windows.go
+++ b/libgo/go/os/exec/lp_windows.go
@@ -18,10 +18,10 @@ func chkStat(file string) error {
 	if err != nil {
 		return err
 	}
-	if d.IsRegular() {
-		return nil
+	if d.IsDir() {
+		return os.EPERM
 	}
-	return os.EPERM
+	return nil
 }
 
 func findExecutable(file string, exts []string) (string, error) {
diff --git a/libgo/go/os/export_test.go b/libgo/go/os/export_test.go
new file mode 100644
index 00000000000..9c6ef429744
--- /dev/null
+++ b/libgo/go/os/export_test.go
@@ -0,0 +1,9 @@
+// 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 os
+
+// Export for testing.
+
+var Atime = atime
diff --git a/libgo/go/os/file.go b/libgo/go/os/file.go
index 386afb889b2..71845d3c9c9 100644
--- a/libgo/go/os/file.go
+++ b/libgo/go/os/file.go
@@ -14,7 +14,7 @@ import (
 )
 
 // Name returns the name of the file as presented to Open.
-func (file *File) Name() string { return file.name }
+func (f *File) Name() string { return f.name }
 
 // Stdin, Stdout, and Stderr are open Files pointing to the standard input,
 // standard output, and standard error file descriptors.
@@ -51,11 +51,11 @@ const (
 // Read reads up to len(b) bytes from the File.
 // It returns the number of bytes read and an error, if any.
 // EOF is signaled by a zero count with err set to io.EOF.
-func (file *File) Read(b []byte) (n int, err error) {
-	if file == nil {
+func (f *File) Read(b []byte) (n int, err error) {
+	if f == nil {
 		return 0, EINVAL
 	}
-	n, e := file.read(b)
+	n, e := f.read(b)
 	if n < 0 {
 		n = 0
 	}
@@ -63,26 +63,26 @@ func (file *File) Read(b []byte) (n int, err error) {
 		return 0, io.EOF
 	}
 	if e != nil {
-		err = &PathError{"read", file.name, e}
+		err = &PathError{"read", f.name, e}
 	}
 	return n, err
 }
 
 // ReadAt reads len(b) bytes from the File starting at byte offset off.
 // It returns the number of bytes read and the error, if any.
-// EOF is signaled by a zero count with err set to io.EOF.
-// ReadAt always returns a non-nil error when n != len(b).
-func (file *File) ReadAt(b []byte, off int64) (n int, err error) {
-	if file == nil {
+// ReadAt always returns a non-nil error when n < len(b).
+// At end of file, that error is io.EOF.
+func (f *File) ReadAt(b []byte, off int64) (n int, err error) {
+	if f == nil {
 		return 0, EINVAL
 	}
 	for len(b) > 0 {
-		m, e := file.pread(b, off)
+		m, e := f.pread(b, off)
 		if m == 0 && e == nil {
 			return n, io.EOF
 		}
 		if e != nil {
-			err = &PathError{"read", file.name, e}
+			err = &PathError{"read", f.name, e}
 			break
 		}
 		n += m
@@ -95,19 +95,19 @@ func (file *File) ReadAt(b []byte, off int64) (n int, err error) {
 // Write writes len(b) bytes to the File.
 // It returns the number of bytes written and an error, if any.
 // Write returns a non-nil error when n != len(b).
-func (file *File) Write(b []byte) (n int, err error) {
-	if file == nil {
+func (f *File) Write(b []byte) (n int, err error) {
+	if f == nil {
 		return 0, EINVAL
 	}
-	n, e := file.write(b)
+	n, e := f.write(b)
 	if n < 0 {
 		n = 0
 	}
 
-	epipecheck(file, e)
+	epipecheck(f, e)
 
 	if e != nil {
-		err = &PathError{"write", file.name, e}
+		err = &PathError{"write", f.name, e}
 	}
 	return n, err
 }
@@ -115,14 +115,14 @@ func (file *File) Write(b []byte) (n int, err error) {
 // WriteAt writes len(b) bytes to the File starting at byte offset off.
 // It returns the number of bytes written and an error, if any.
 // WriteAt returns a non-nil error when n != len(b).
-func (file *File) WriteAt(b []byte, off int64) (n int, err error) {
-	if file == nil {
+func (f *File) WriteAt(b []byte, off int64) (n int, err error) {
+	if f == nil {
 		return 0, EINVAL
 	}
 	for len(b) > 0 {
-		m, e := file.pwrite(b, off)
+		m, e := f.pwrite(b, off)
 		if e != nil {
-			err = &PathError{"write", file.name, e}
+			err = &PathError{"write", f.name, e}
 			break
 		}
 		n += m
@@ -136,24 +136,24 @@ func (file *File) WriteAt(b []byte, off int64) (n int, err error) {
 // according to whence: 0 means relative to the origin of the file, 1 means
 // relative to the current offset, and 2 means relative to the end.
 // It returns the new offset and an error, if any.
-func (file *File) Seek(offset int64, whence int) (ret int64, err error) {
-	r, e := file.seek(offset, whence)
-	if e == nil && file.dirinfo != nil && r != 0 {
+func (f *File) Seek(offset int64, whence int) (ret int64, err error) {
+	r, e := f.seek(offset, whence)
+	if e == nil && f.dirinfo != nil && r != 0 {
 		e = syscall.EISDIR
 	}
 	if e != nil {
-		return 0, &PathError{"seek", file.name, e}
+		return 0, &PathError{"seek", f.name, e}
 	}
 	return r, nil
 }
 
 // WriteString is like Write, but writes the contents of string s rather than
 // an array of bytes.
-func (file *File) WriteString(s string) (ret int, err error) {
-	if file == nil {
+func (f *File) WriteString(s string) (ret int, err error) {
+	if f == nil {
 		return 0, EINVAL
 	}
-	return file.Write([]byte(s))
+	return f.Write([]byte(s))
 }
 
 // Mkdir creates a new directory with the specified name and permission bits.
diff --git a/libgo/go/os/file_posix.go b/libgo/go/os/file_posix.go
index c80d3df5e50..a4ab5d6ae25 100644
--- a/libgo/go/os/file_posix.go
+++ b/libgo/go/os/file_posix.go
@@ -8,6 +8,7 @@ package os
 
 import (
 	"syscall"
+	"time"
 )
 
 func sigpipe() // implemented in package runtime
@@ -168,11 +169,11 @@ func (f *File) Truncate(size int64) error {
 // Sync commits the current contents of the file to stable storage.
 // Typically, this means flushing the file system's in-memory copy
 // of recently written data to disk.
-func (file *File) Sync() (err error) {
-	if file == nil {
+func (f *File) Sync() (err error) {
+	if f == nil {
 		return EINVAL
 	}
-	if e := syscall.Fsync(file.fd); e != nil {
+	if e := syscall.Fsync(f.fd); e != nil {
 		return NewSyscallError("fsync", e)
 	}
 	return nil
@@ -181,11 +182,12 @@ func (file *File) Sync() (err error) {
 // Chtimes changes the access and modification times of the named
 // file, similar to the Unix utime() or utimes() functions.
 //
-// The argument times are in nanoseconds, although the underlying
-// filesystem may truncate or round the values to a more
-// coarse time unit.
-func Chtimes(name string, atime_ns int64, mtime_ns int64) error {
+// The underlying filesystem may truncate or round the values to a
+// less precise time unit.
+func Chtimes(name string, atime time.Time, mtime time.Time) error {
 	var utimes [2]syscall.Timeval
+	atime_ns := atime.Unix()*1e9 + int64(atime.Nanosecond())
+	mtime_ns := mtime.Unix()*1e9 + int64(mtime.Nanosecond())
 	utimes[0] = syscall.NsecToTimeval(atime_ns)
 	utimes[1] = syscall.NsecToTimeval(mtime_ns)
 	if e := syscall.Utimes(name, utimes[0:]); e != nil {
diff --git a/libgo/go/os/file_unix.go b/libgo/go/os/file_unix.go
index 0bf31ecb9a7..671d1a4cb62 100644
--- a/libgo/go/os/file_unix.go
+++ b/libgo/go/os/file_unix.go
@@ -28,11 +28,11 @@ type file struct {
 }
 
 // Fd returns the integer Unix file descriptor referencing the open file.
-func (file *File) Fd() int {
-	if file == nil {
+func (f *File) Fd() int {
+	if f == nil {
 		return -1
 	}
-	return file.fd
+	return f.fd
 }
 
 // NewFile returns a new File with the given file descriptor and name.
@@ -77,8 +77,8 @@ func OpenFile(name string, flag int, perm uint32) (file *File, err error) {
 
 // Close closes the File, rendering it unusable for I/O.
 // It returns an error, if any.
-func (file *File) Close() error {
-	return file.file.close()
+func (f *File) Close() error {
+	return f.file.close()
 }
 
 func (file *file) close() error {
@@ -105,50 +105,43 @@ func (file *file) close() error {
 
 // Stat returns the FileInfo structure describing file.
 // It returns the FileInfo and an error, if any.
-func (file *File) Stat() (fi *FileInfo, err error) {
+func (f *File) Stat() (fi FileInfo, err error) {
 	var stat syscall.Stat_t
-	e := syscall.Fstat(file.fd, &stat)
-	if e != nil {
-		return nil, &PathError{"stat", file.name, e}
+	err = syscall.Fstat(f.fd, &stat)
+	if err != nil {
+		return nil, &PathError{"stat", f.name, err}
 	}
-	return fileInfoFromStat(file.name, new(FileInfo), &stat, &stat), nil
+	return fileInfoFromStat(&stat, f.name), nil
 }
 
-// Stat returns a FileInfo structure describing the named file and an error, if any.
+// Stat returns a FileInfo describing the named file and an error, if any.
 // If name names a valid symbolic link, the returned FileInfo describes
 // the file pointed at by the link and has fi.FollowedSymlink set to true.
 // If name names an invalid symbolic link, the returned FileInfo describes
 // the link itself and has fi.FollowedSymlink set to false.
-func Stat(name string) (fi *FileInfo, err error) {
-	var lstat, stat syscall.Stat_t
-	e := syscall.Lstat(name, &lstat)
-	if e != nil {
-		return nil, &PathError{"stat", name, e}
+func Stat(name string) (fi FileInfo, err error) {
+	var stat syscall.Stat_t
+	err = syscall.Stat(name, &stat)
+	if err != nil {
+		return nil, &PathError{"stat", name, err}
 	}
-	statp := &lstat
-	if lstat.Mode&syscall.S_IFMT == syscall.S_IFLNK {
-		e := syscall.Stat(name, &stat)
-		if e == nil {
-			statp = &stat
-		}
-	}
-	return fileInfoFromStat(name, new(FileInfo), &lstat, statp), nil
+	return fileInfoFromStat(&stat, name), nil
 }
 
-// Lstat returns the FileInfo structure describing the named file and an
+// Lstat returns a FileInfo describing the named file and an
 // error, if any.  If the file is a symbolic link, the returned FileInfo
 // describes the symbolic link.  Lstat makes no attempt to follow the link.
-func Lstat(name string) (fi *FileInfo, err error) {
+func Lstat(name string) (fi FileInfo, err error) {
 	var stat syscall.Stat_t
-	e := syscall.Lstat(name, &stat)
-	if e != nil {
-		return nil, &PathError{"lstat", name, e}
+	err = syscall.Lstat(name, &stat)
+	if err != nil {
+		return nil, &PathError{"lstat", name, err}
 	}
-	return fileInfoFromStat(name, new(FileInfo), &stat, &stat), nil
+	return fileInfoFromStat(&stat, name), nil
 }
 
 // Readdir reads the contents of the directory associated with file and
-// returns an array of up to n FileInfo structures, as would be returned
+// 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.
 //
@@ -162,23 +155,23 @@ func Lstat(name string) (fi *FileInfo, err error) {
 // 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) {
-	dirname := file.name
+func (f *File) Readdir(n int) (fi []FileInfo, err error) {
+	dirname := f.name
 	if dirname == "" {
 		dirname = "."
 	}
 	dirname += "/"
-	names, err := file.Readdirnames(n)
+	names, err := f.Readdirnames(n)
 	fi = make([]FileInfo, len(names))
 	for i, filename := range names {
 		fip, err := Lstat(dirname + filename)
-		if fip == nil || err != nil {
-			fi[i].Name = filename // rest is already zeroed out
+		if err == nil {
+			fi[i] = fip
 		} else {
-			fi[i] = *fip
+			fi[i] = &FileStat{name: filename}
 		}
 	}
-	return
+	return fi, err
 }
 
 // read reads up to len(b) bytes from the File.
diff --git a/libgo/go/os/getwd.go b/libgo/go/os/getwd.go
index d5f5ae6bed7..a0d3c99a503 100644
--- a/libgo/go/os/getwd.go
+++ b/libgo/go/os/getwd.go
@@ -12,7 +12,7 @@ import (
 // current directory.  If the current directory can be
 // reached via multiple paths (due to symbolic links),
 // Getwd may return any one of them.
-func Getwd() (string, error) {
+func Getwd() (pwd string, err error) {
 	// If the operating system provides a Getwd call, use it.
 	if syscall.ImplementsGetwd {
 		s, e := syscall.Getwd()
@@ -27,10 +27,10 @@ func Getwd() (string, error) {
 
 	// Clumsy but widespread kludge:
 	// if $PWD is set and matches ".", use it.
-	pwd := Getenv("PWD")
+	pwd = Getenv("PWD")
 	if len(pwd) > 0 && pwd[0] == '/' {
 		d, err := Stat(pwd)
-		if err == nil && d.Dev == dot.Dev && d.Ino == dot.Ino {
+		if err == nil && dot.(*FileStat).SameFile(d.(*FileStat)) {
 			return pwd, nil
 		}
 	}
@@ -42,7 +42,7 @@ func Getwd() (string, error) {
 		// Can't stat root - no hope.
 		return "", err
 	}
-	if root.Dev == dot.Dev && root.Ino == dot.Ino {
+	if root.(*FileStat).SameFile(dot.(*FileStat)) {
 		return "/", nil
 	}
 
@@ -67,7 +67,7 @@ func Getwd() (string, error) {
 			}
 			for _, name := range names {
 				d, _ := Lstat(parent + "/" + name)
-				if d.Dev == dot.Dev && d.Ino == dot.Ino {
+				if d.(*FileStat).SameFile(dot.(*FileStat)) {
 					pwd = "/" + name + pwd
 					goto Found
 				}
@@ -82,7 +82,7 @@ func Getwd() (string, error) {
 			return "", err
 		}
 		fd.Close()
-		if pd.Dev == root.Dev && pd.Ino == root.Ino {
+		if pd.(*FileStat).SameFile(root.(*FileStat)) {
 			break
 		}
 		// Set up for next round.
diff --git a/libgo/go/os/os_test.go b/libgo/go/os/os_test.go
index 170f7331c6e..299d2e86155 100644
--- a/libgo/go/os/os_test.go
+++ b/libgo/go/os/os_test.go
@@ -14,6 +14,7 @@ import (
 	"strings"
 	"syscall"
 	"testing"
+	"time"
 )
 
 var dot = []string{
@@ -119,12 +120,12 @@ func TestStat(t *testing.T) {
 	if err != nil {
 		t.Fatal("stat failed:", err)
 	}
-	if !equal(sfname, dir.Name) {
-		t.Error("name should be ", sfname, "; is", dir.Name)
+	if !equal(sfname, dir.Name()) {
+		t.Error("name should be ", sfname, "; is", dir.Name())
 	}
 	filesize := size(path, t)
-	if dir.Size != filesize {
-		t.Error("size should be", filesize, "; is", dir.Size)
+	if dir.Size() != filesize {
+		t.Error("size should be", filesize, "; is", dir.Size())
 	}
 }
 
@@ -139,12 +140,12 @@ func TestFstat(t *testing.T) {
 	if err2 != nil {
 		t.Fatal("fstat failed:", err2)
 	}
-	if !equal(sfname, dir.Name) {
-		t.Error("name should be ", sfname, "; is", dir.Name)
+	if !equal(sfname, dir.Name()) {
+		t.Error("name should be ", sfname, "; is", dir.Name())
 	}
 	filesize := size(path, t)
-	if dir.Size != filesize {
-		t.Error("size should be", filesize, "; is", dir.Size)
+	if dir.Size() != filesize {
+		t.Error("size should be", filesize, "; is", dir.Size())
 	}
 }
 
@@ -154,12 +155,12 @@ func TestLstat(t *testing.T) {
 	if err != nil {
 		t.Fatal("lstat failed:", err)
 	}
-	if !equal(sfname, dir.Name) {
-		t.Error("name should be ", sfname, "; is", dir.Name)
+	if !equal(sfname, dir.Name()) {
+		t.Error("name should be ", sfname, "; is", dir.Name())
 	}
 	filesize := size(path, t)
-	if dir.Size != filesize {
-		t.Error("size should be", filesize, "; is", dir.Size)
+	if dir.Size() != filesize {
+		t.Error("size should be", filesize, "; is", dir.Size())
 	}
 }
 
@@ -226,7 +227,7 @@ func testReaddir(dir string, contents []string, t *testing.T) {
 	for _, m := range contents {
 		found := false
 		for _, n := range s {
-			if equal(m, n.Name) {
+			if equal(m, n.Name()) {
 				if found {
 					t.Error("present twice:", m)
 				}
@@ -405,7 +406,7 @@ func TestHardLink(t *testing.T) {
 	if err != nil {
 		t.Fatalf("stat %q failed: %v", from, err)
 	}
-	if tostat.Dev != fromstat.Dev || tostat.Ino != fromstat.Ino {
+	if !tostat.(*FileStat).SameFile(fromstat.(*FileStat)) {
 		t.Errorf("link %q, %q did not create hard link", to, from)
 	}
 }
@@ -430,32 +431,32 @@ func TestSymLink(t *testing.T) {
 		t.Fatalf("symlink %q, %q failed: %v", to, from, err)
 	}
 	defer Remove(from)
-	tostat, err := Stat(to)
+	tostat, err := Lstat(to)
 	if err != nil {
 		t.Fatalf("stat %q failed: %v", to, err)
 	}
-	if tostat.FollowedSymlink {
-		t.Fatalf("stat %q claims to have followed a symlink", to)
+	if tostat.Mode()&ModeSymlink != 0 {
+		t.Fatalf("stat %q claims to have found a symlink", to)
 	}
 	fromstat, err := Stat(from)
 	if err != nil {
 		t.Fatalf("stat %q failed: %v", from, err)
 	}
-	if tostat.Dev != fromstat.Dev || tostat.Ino != fromstat.Ino {
+	if !tostat.(*FileStat).SameFile(fromstat.(*FileStat)) {
 		t.Errorf("symlink %q, %q did not create symlink", to, from)
 	}
 	fromstat, err = Lstat(from)
 	if err != nil {
 		t.Fatalf("lstat %q failed: %v", from, err)
 	}
-	if !fromstat.IsSymlink() {
+	if fromstat.Mode()&ModeSymlink == 0 {
 		t.Fatalf("symlink %q, %q did not create symlink", to, from)
 	}
 	fromstat, err = Stat(from)
 	if err != nil {
 		t.Fatalf("stat %q failed: %v", from, err)
 	}
-	if !fromstat.FollowedSymlink {
+	if fromstat.Mode()&ModeSymlink != 0 {
 		t.Fatalf("stat %q did not follow symlink", from)
 	}
 	s, err := Readlink(from)
@@ -563,13 +564,13 @@ func TestStartProcess(t *testing.T) {
 	exec(t, cmddir, cmdbase, args, filepath.Clean(cmddir)+le)
 }
 
-func checkMode(t *testing.T, path string, mode uint32) {
+func checkMode(t *testing.T, path string, mode FileMode) {
 	dir, err := Stat(path)
 	if err != nil {
 		t.Fatalf("Stat %q (looking for mode %#o): %s", path, mode, err)
 	}
-	if dir.Mode&0777 != mode {
-		t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode, mode)
+	if dir.Mode()&0777 != mode {
+		t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode(), mode)
 	}
 }
 
@@ -593,73 +594,13 @@ func TestChmod(t *testing.T) {
 	checkMode(t, f.Name(), 0123)
 }
 
-func checkUidGid(t *testing.T, path string, uid, gid int) {
-	dir, err := Stat(path)
-	if err != nil {
-		t.Fatalf("Stat %q (looking for uid/gid %d/%d): %s", path, uid, gid, err)
-	}
-	if dir.Uid != uid {
-		t.Errorf("Stat %q: uid %d want %d", path, dir.Uid, uid)
-	}
-	if dir.Gid != gid {
-		t.Errorf("Stat %q: gid %d want %d", path, dir.Gid, gid)
-	}
-}
-
-func TestChown(t *testing.T) {
-	// Chown is not supported under windows or Plan 9.
-	// Plan9 provides a native ChownPlan9 version instead.
-	if syscall.OS == "windows" || syscall.OS == "plan9" {
-		return
-	}
-	// Use TempDir() to make sure we're on a local file system,
-	// so that the group ids returned by Getgroups will be allowed
-	// on the file.  On NFS, the Getgroups groups are
-	// basically useless.
-	f := newFile("TestChown", t)
-	defer Remove(f.Name())
-	defer f.Close()
-	dir, err := f.Stat()
-	if err != nil {
-		t.Fatalf("stat %s: %s", f.Name(), err)
-	}
-
-	// Can't change uid unless root, but can try
-	// changing the group id.  First try our current group.
-	gid := Getgid()
-	t.Log("gid:", gid)
-	if err = Chown(f.Name(), -1, gid); err != nil {
-		t.Fatalf("chown %s -1 %d: %s", f.Name(), gid, err)
-	}
-	checkUidGid(t, f.Name(), dir.Uid, gid)
-
-	// Then try all the auxiliary groups.
-	groups, err := Getgroups()
-	if err != nil {
-		t.Fatalf("getgroups: %s", err)
-	}
-	t.Log("groups: ", groups)
-	for _, g := range groups {
-		if err = Chown(f.Name(), -1, g); err != nil {
-			t.Fatalf("chown %s -1 %d: %s", f.Name(), g, err)
-		}
-		checkUidGid(t, f.Name(), dir.Uid, g)
-
-		// change back to gid to test fd.Chown
-		if err = f.Chown(-1, gid); err != nil {
-			t.Fatalf("fchown %s -1 %d: %s", f.Name(), gid, err)
-		}
-		checkUidGid(t, f.Name(), dir.Uid, gid)
-	}
-}
-
 func checkSize(t *testing.T, f *File, size int64) {
 	dir, err := f.Stat()
 	if err != nil {
 		t.Fatalf("Stat %q (looking for size %d): %s", f.Name(), size, err)
 	}
-	if dir.Size != size {
-		t.Errorf("Stat %q: size %d want %d", f.Name(), dir.Size, size)
+	if dir.Size() != size {
+		t.Errorf("Stat %q: size %d want %d", f.Name(), dir.Size(), size)
 	}
 }
 
@@ -711,37 +652,38 @@ func TestChtimes(t *testing.T) {
 	f.Write([]byte("hello, world\n"))
 	f.Close()
 
-	preStat, err := Stat(f.Name())
+	st, err := Stat(f.Name())
 	if err != nil {
 		t.Fatalf("Stat %s: %s", f.Name(), err)
 	}
+	preStat := st.(*FileStat)
 
 	// Move access and modification time back a second
-	const OneSecond = 1e9 // in nanoseconds
-	err = Chtimes(f.Name(), preStat.Atime_ns-OneSecond, preStat.Mtime_ns-OneSecond)
+	at := Atime(preStat)
+	mt := preStat.ModTime()
+	err = Chtimes(f.Name(), at.Add(-time.Second), mt.Add(-time.Second))
 	if err != nil {
 		t.Fatalf("Chtimes %s: %s", f.Name(), err)
 	}
 
-	postStat, err := Stat(f.Name())
+	st, err = Stat(f.Name())
 	if err != nil {
 		t.Fatalf("second Stat %s: %s", f.Name(), err)
 	}
+	postStat := st.(*FileStat)
 
 	/* Plan 9:
 		Mtime is the time of the last change of content.  Similarly, atime is set whenever the
 	    contents are accessed; also, it is set whenever mtime is set.
 	*/
-	if postStat.Atime_ns >= preStat.Atime_ns && syscall.OS != "plan9" {
-		t.Errorf("Atime_ns didn't go backwards; was=%d, after=%d",
-			preStat.Atime_ns,
-			postStat.Atime_ns)
+	pat := Atime(postStat)
+	pmt := postStat.ModTime()
+	if !pat.Before(at) && syscall.OS != "plan9" {
+		t.Errorf("AccessTime didn't go backwards; was=%d, after=%d", at, pat)
 	}
 
-	if postStat.Mtime_ns >= preStat.Mtime_ns {
-		t.Errorf("Mtime_ns didn't go backwards; was=%d, after=%d",
-			preStat.Mtime_ns,
-			postStat.Mtime_ns)
+	if !pmt.Before(mt) {
+		t.Errorf("ModTime didn't go backwards; was=%d, after=%d", mt, pmt)
 	}
 }
 
@@ -883,7 +825,7 @@ func TestOpenError(t *testing.T) {
 		}
 		perr, ok := err.(*PathError)
 		if !ok {
-			t.Errorf("Open(%q, %d) returns error of %T type; want *os.PathError", tt.path, tt.mode, err)
+			t.Errorf("Open(%q, %d) returns error of %T type; want *PathError", tt.path, tt.mode, err)
 		}
 		if perr.Err != tt.error {
 			if syscall.OS == "plan9" {
@@ -899,6 +841,14 @@ func TestOpenError(t *testing.T) {
 	}
 }
 
+func TestOpenNoName(t *testing.T) {
+	f, err := Open("")
+	if err == nil {
+		t.Fatal(`Open("") succeeded`)
+		f.Close()
+	}
+}
+
 func run(t *testing.T, cmd []string) string {
 	// Run /bin/hostname and collect output.
 	r, w, err := Pipe()
diff --git a/libgo/go/os/os_unix_test.go b/libgo/go/os/os_unix_test.go
new file mode 100644
index 00000000000..3109a8171a5
--- /dev/null
+++ b/libgo/go/os/os_unix_test.go
@@ -0,0 +1,75 @@
+// 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.
+
+// +build darwin freebsd linux openbsd
+
+package os_test
+
+import (
+	. "os"
+	"syscall"
+	"testing"
+)
+
+func checkUidGid(t *testing.T, path string, uid, gid int) {
+	dir, err := Stat(path)
+	if err != nil {
+		t.Fatalf("Stat %q (looking for uid/gid %d/%d): %s", path, uid, gid, err)
+	}
+	sys := dir.(*FileStat).Sys.(*syscall.Stat_t)
+	if int(sys.Uid) != uid {
+		t.Errorf("Stat %q: uid %d want %d", path, sys.Uid, uid)
+	}
+	if int(sys.Gid) != gid {
+		t.Errorf("Stat %q: gid %d want %d", path, sys.Gid, gid)
+	}
+}
+
+func TestChown(t *testing.T) {
+	// Chown is not supported under windows or Plan 9.
+	// Plan9 provides a native ChownPlan9 version instead.
+	if syscall.OS == "windows" || syscall.OS == "plan9" {
+		return
+	}
+	// Use TempDir() to make sure we're on a local file system,
+	// so that the group ids returned by Getgroups will be allowed
+	// on the file.  On NFS, the Getgroups groups are
+	// basically useless.
+	f := newFile("TestChown", t)
+	defer Remove(f.Name())
+	defer f.Close()
+	dir, err := f.Stat()
+	if err != nil {
+		t.Fatalf("stat %s: %s", f.Name(), err)
+	}
+
+	// Can't change uid unless root, but can try
+	// changing the group id.  First try our current group.
+	gid := Getgid()
+	t.Log("gid:", gid)
+	if err = Chown(f.Name(), -1, gid); err != nil {
+		t.Fatalf("chown %s -1 %d: %s", f.Name(), gid, err)
+	}
+	sys := dir.(*FileStat).Sys.(*syscall.Stat_t)
+	checkUidGid(t, f.Name(), int(sys.Uid), gid)
+
+	// Then try all the auxiliary groups.
+	groups, err := Getgroups()
+	if err != nil {
+		t.Fatalf("getgroups: %s", err)
+	}
+	t.Log("groups: ", groups)
+	for _, g := range groups {
+		if err = Chown(f.Name(), -1, g); err != nil {
+			t.Fatalf("chown %s -1 %d: %s", f.Name(), g, err)
+		}
+		checkUidGid(t, f.Name(), int(sys.Uid), g)
+
+		// change back to gid to test fd.Chown
+		if err = f.Chown(-1, gid); err != nil {
+			t.Fatalf("fchown %s -1 %d: %s", f.Name(), gid, err)
+		}
+		checkUidGid(t, f.Name(), int(sys.Uid), gid)
+	}
+}
diff --git a/libgo/go/os/path.go b/libgo/go/os/path.go
index 82fade63ae2..bc14a783188 100644
--- a/libgo/go/os/path.go
+++ b/libgo/go/os/path.go
@@ -17,7 +17,7 @@ func MkdirAll(path string, perm uint32) error {
 	// If path exists, stop with success or error.
 	dir, err := Stat(path)
 	if err == nil {
-		if dir.IsDirectory() {
+		if dir.IsDir() {
 			return nil
 		}
 		return &PathError{"mkdir", path, ENOTDIR}
@@ -48,7 +48,7 @@ func MkdirAll(path string, perm uint32) error {
 		// Handle arguments like "foo/." by
 		// double-checking that directory doesn't exist.
 		dir, err1 := Lstat(path)
-		if err1 == nil && dir.IsDirectory() {
+		if err1 == nil && dir.IsDir() {
 			return nil
 		}
 		return err
@@ -75,7 +75,7 @@ func RemoveAll(path string) error {
 		}
 		return serr
 	}
-	if !dir.IsDirectory() {
+	if !dir.IsDir() {
 		// Not a directory; return the error from Remove.
 		return err
 	}
diff --git a/libgo/go/os/stat.go b/libgo/go/os/stat.go
index 8eb4ab4391d..c664fc189b8 100644
--- a/libgo/go/os/stat.go
+++ b/libgo/go/os/stat.go
@@ -2,39 +2,55 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// AMD64, Linux
-
 package os
 
-import syscall "syscall"
+import (
+	"syscall"
+	"time"
+)
 
-func isSymlink(stat *syscall.Stat_t) bool {
-	return stat.Mode & syscall.S_IFMT == syscall.S_IFLNK
+func sameFile(fs1, fs2 *FileStat) bool {
+	sys1 := fs1.Sys.(*syscall.Stat_t)
+	sys2 := fs2.Sys.(*syscall.Stat_t)
+	return sys1.Dev == sys2.Dev && sys1.Ino == sys2.Ino
 }
 
-func fileInfoFromStat(name string, fi *FileInfo, lstat, stat *syscall.Stat_t) *FileInfo {
-	fi.Dev = uint64(stat.Dev)
-	fi.Ino = uint64(stat.Ino)
-	fi.Nlink = uint64(stat.Nlink)
-	fi.Mode = uint32(stat.Mode)
-	fi.Uid = int(stat.Uid)
-	fi.Gid = int(stat.Gid)
-	fi.Rdev = uint64(stat.Rdev)
-	fi.Size = int64(stat.Size)
-	fi.Blksize = int64(stat.Blksize)
-	fi.Blocks = int64(stat.Blocks)
-	fi.Atime_ns = int64(stat.Atime.Sec)*1e9 + int64(stat.Atime.Nsec)
-	fi.Mtime_ns = int64(stat.Mtime.Sec)*1e9 + int64(stat.Mtime.Nsec)
-	fi.Ctime_ns = int64(stat.Ctime.Sec)*1e9 + int64(stat.Ctime.Nsec)
-	for i := len(name)-1; i >= 0; i-- {
-		if name[i] == '/' {
-			name = name[i+1:]
-			break
-		}
+func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
+	fs := &FileStat{
+		name:    basename(name),
+		size:    int64(st.Size),
+		modTime: timespecToTime(st.Mtime),
+		Sys:     st,
 	}
-	fi.Name = name
-	if isSymlink(lstat) && !isSymlink(stat) {
-		fi.FollowedSymlink = true
+	fs.mode = FileMode(st.Mode & 0777)
+	switch st.Mode & syscall.S_IFMT {
+	case syscall.S_IFBLK, syscall.S_IFCHR:
+		fs.mode |= ModeDevice
+	case syscall.S_IFDIR:
+		fs.mode |= ModeDir
+	case syscall.S_IFIFO:
+		fs.mode |= ModeNamedPipe
+	case syscall.S_IFLNK:
+		fs.mode |= ModeSymlink
+	case syscall.S_IFREG:
+		// nothing to do
+	case syscall.S_IFSOCK:
+		fs.mode |= ModeSocket
 	}
-	return fi
+	if st.Mode&syscall.S_ISGID != 0 {
+		fs.mode |= ModeSetgid
+	}
+	if st.Mode&syscall.S_ISUID != 0 {
+		fs.mode |= ModeSetuid
+	}
+	return fs
+}
+
+func timespecToTime(ts syscall.Timespec) time.Time {
+	return time.Unix(int64(ts.Sec), int64(ts.Nsec))
+}
+
+// For testing.
+func atime(fi FileInfo) time.Time {
+	return timespecToTime(fi.(*FileStat).Sys.(*syscall.Stat_t).Atime)
 }
diff --git a/libgo/go/os/stat_openbsd.go b/libgo/go/os/stat_openbsd.go
index 6d3a3813b09..66189a6b9ba 100644
--- a/libgo/go/os/stat_openbsd.go
+++ b/libgo/go/os/stat_openbsd.go
@@ -4,29 +4,53 @@
 
 package os
 
-import "syscall"
+import (
+	"syscall"
+	"time"
+)
 
-func isSymlink(stat *syscall.Stat_t) bool {
-	return stat.Mode&syscall.S_IFMT == syscall.S_IFLNK
+func sameFile(fs1, fs2 *FileStat) bool {
+	sys1 := fs1.Sys.(*syscall.Stat_t)
+	sys2 := fs2.Sys.(*syscall.Stat_t)
+	return sys1.Dev == sys2.Dev && sys1.Ino == sys2.Ino
 }
 
-func fileInfoFromStat(name string, fi *FileInfo, lstat, stat *syscall.Stat_t) *FileInfo {
-	fi.Dev = uint64(stat.Dev)
-	fi.Ino = uint64(stat.Ino)
-	fi.Nlink = uint64(stat.Nlink)
-	fi.Mode = uint32(stat.Mode)
-	fi.Uid = int(stat.Uid)
-	fi.Gid = int(stat.Gid)
-	fi.Rdev = uint64(stat.Rdev)
-	fi.Size = int64(stat.Size)
-	fi.Blksize = int64(stat.Blksize)
-	fi.Blocks = stat.Blocks
-	fi.Atime_ns = syscall.TimespecToNsec(stat.Atim)
-	fi.Mtime_ns = syscall.TimespecToNsec(stat.Mtim)
-	fi.Ctime_ns = syscall.TimespecToNsec(stat.Ctim)
-	fi.Name = basename(name)
-	if isSymlink(lstat) && !isSymlink(stat) {
-		fi.FollowedSymlink = true
+func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
+	fs := &FileStat{
+		name:    basename(name),
+		size:    int64(st.Size),
+		modTime: timespecToTime(st.Mtim),
+		Sys:     st,
 	}
-	return fi
+	fs.mode = FileMode(st.Mode & 0777)
+	switch st.Mode & syscall.S_IFMT {
+	case syscall.S_IFBLK, syscall.S_IFCHR:
+		fs.mode |= ModeDevice
+	case syscall.S_IFDIR:
+		fs.mode |= ModeDir
+	case syscall.S_IFIFO:
+		fs.mode |= ModeNamedPipe
+	case syscall.S_IFLNK:
+		fs.mode |= ModeSymlink
+	case syscall.S_IFREG:
+		// nothing to do
+	case syscall.S_IFSOCK:
+		fs.mode |= ModeSocket
+	}
+	if st.Mode&syscall.S_ISGID != 0 {
+		fs.mode |= ModeSetgid
+	}
+	if st.Mode&syscall.S_ISUID != 0 {
+		fs.mode |= ModeSetuid
+	}
+	return fs
+}
+
+func timespecToTime(ts syscall.Timespec) time.Time {
+	return time.Unix(int64(ts.Sec), int64(ts.Nsec))
+}
+
+// For testing.
+func atime(fi FileInfo) time.Time {
+	return timespecToTime(fi.(*FileStat).Sys.(*syscall.Stat_t).Atim)
 }
diff --git a/libgo/go/os/types.go b/libgo/go/os/types.go
index df57b59a388..2638153ddbe 100644
--- a/libgo/go/os/types.go
+++ b/libgo/go/os/types.go
@@ -4,53 +4,111 @@
 
 package os
 
-import "syscall"
-
-// An operating-system independent representation of Unix data structures.
-// OS-specific routines in this directory convert the OS-local versions to these.
+import (
+	"syscall"
+	"time"
+)
 
 // Getpagesize returns the underlying system's memory page size.
 func Getpagesize() int { return syscall.Getpagesize() }
 
-// A FileInfo describes a file and is returned by Stat, Fstat, and Lstat
-type FileInfo struct {
-	Dev             uint64 // device number of file system holding file.
-	Ino             uint64 // inode number.
-	Nlink           uint64 // number of hard links.
-	Mode            uint32 // permission and mode bits.
-	Uid             int    // user id of owner.
-	Gid             int    // group id of owner.
-	Rdev            uint64 // device type for special file.
-	Size            int64  // length in bytes.
-	Blksize         int64  // size of blocks, in bytes.
-	Blocks          int64  // number of blocks allocated for file.
-	Atime_ns        int64  // access time; nanoseconds since epoch.
-	Mtime_ns        int64  // modified time; nanoseconds since epoch.
-	Ctime_ns        int64  // status change time; nanoseconds since epoch.
-	Name            string // base name of the file name provided in Open, Stat, etc.
-	FollowedSymlink bool   // followed a symlink to get this information
+// A FileInfo describes a file and is returned by Stat and Lstat
+type FileInfo interface {
+	Name() string       // base name of the file
+	Size() int64        // length in bytes
+	Mode() FileMode     // file mode bits
+	ModTime() time.Time // modification time
+	IsDir() bool        // abbreviation for Mode().IsDir()
 }
 
-// IsFifo reports whether the FileInfo describes a FIFO file.
-func (f *FileInfo) IsFifo() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFIFO }
+// A FileMode represents a file's mode and permission bits.
+// The bits have the same definition on all systems, so that
+// information about files can be moved from one system
+// to another portably.  Not all bits apply to all systems.
+// The only required bit is ModeDir for directories.
+type FileMode uint32
 
-// IsChar reports whether the FileInfo describes a character special file.
-func (f *FileInfo) IsChar() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFCHR }
+// The defined file mode bits are the most significant bits of the FileMode.
+// The nine least-significant bits are the standard Unix rwxrwxrwx permissions.
+const (
+	// The single letters are the abbreviations
+	// used by the String method's formatting.
+	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)
+	ModeSymlink                                   // L: symbolic link
+	ModeDevice                                    // D: device file
+	ModeNamedPipe                                 // p: named pipe (FIFO)
+	ModeSocket                                    // S: Unix domain socket
+	ModeSetuid                                    // u: setuid
+	ModeSetgid                                    // g: setgid
 
-// IsDirectory reports whether the FileInfo describes a directory.
-func (f *FileInfo) IsDirectory() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFDIR }
+	// Mask for the type bits. For regular files, none will be set.
+	ModeType = ModeDir | ModeSymlink | ModeNamedPipe | ModeSocket | ModeDevice
 
-// IsBlock reports whether the FileInfo describes a block special file.
-func (f *FileInfo) IsBlock() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFBLK }
+	ModePerm FileMode = 0777 // permission bits
+)
 
-// IsRegular reports whether the FileInfo describes a regular file.
-func (f *FileInfo) IsRegular() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFREG }
+func (m FileMode) String() string {
+	const str = "daltLDpSug"
+	var buf [20]byte
+	w := 0
+	for i, c := range str {
+		if m&(1<<uint(32-1-i)) != 0 {
+			buf[w] = byte(c)
+			w++
+		}
+	}
+	if w == 0 {
+		buf[w] = '-'
+		w++
+	}
+	const rwx = "rwxrwxrwx"
+	for i, c := range rwx {
+		if m&(1<<uint(9-1-i)) != 0 {
+			buf[w] = byte(c)
+		} else {
+			buf[w] = '-'
+		}
+		w++
+	}
+	return string(buf[:w])
+}
 
-// IsSymlink reports whether the FileInfo describes a symbolic link.
-func (f *FileInfo) IsSymlink() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFLNK }
+// IsDir reports whether m describes a directory.
+// That is, it tests for the ModeDir bit being set in m.
+func (m FileMode) IsDir() bool {
+	return m&ModeDir != 0
+}
 
-// IsSocket reports whether the FileInfo describes a socket.
-func (f *FileInfo) IsSocket() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFSOCK }
+// Perm returns the Unix permission bits in m.
+func (m FileMode) Perm() FileMode {
+	return m & ModePerm
+}
 
-// Permission returns the file permission bits.
-func (f *FileInfo) Permission() uint32 { return f.Mode & 0777 }
+// A FileStat is the implementation of FileInfo returned by Stat and Lstat.
+// Clients that need access to the underlying system-specific stat information
+// can test for *os.FileStat and then consult the Sys field.
+type FileStat struct {
+	name    string
+	size    int64
+	mode    FileMode
+	modTime time.Time
+
+	Sys interface{}
+}
+
+func (fs *FileStat) Name() string       { return fs.name }
+func (fs *FileStat) Size() int64        { return fs.size }
+func (fs *FileStat) Mode() FileMode     { return fs.mode }
+func (fs *FileStat) ModTime() time.Time { return fs.modTime }
+func (fs *FileStat) IsDir() bool        { return fs.mode.IsDir() }
+
+// SameFile reports whether fs and other describe the same file.
+// For example, on Unix this means that the device and inode fields
+// of the two underlying structures are identical; on other systems
+// the decision may be based on the path names.
+func (fs *FileStat) SameFile(other *FileStat) bool {
+	return sameFile(fs, other)
+}
diff --git a/libgo/go/os/user/user_test.go b/libgo/go/os/user/user_test.go
index 59f15e4c675..f9f44af8a93 100644
--- a/libgo/go/os/user/user_test.go
+++ b/libgo/go/os/user/user_test.go
@@ -41,8 +41,8 @@ func TestLookup(t *testing.T) {
 		t.Errorf("expected Uid of %d; got %d", e, g)
 	}
 	fi, err := os.Stat(u.HomeDir)
-	if err != nil || !fi.IsDirectory() {
-		t.Errorf("expected a valid HomeDir; stat(%q): err=%v, IsDirectory=%v", u.HomeDir, err, fi.IsDirectory())
+	if err != nil || !fi.IsDir() {
+		t.Errorf("expected a valid HomeDir; stat(%q): err=%v, IsDir=%v", u.HomeDir, err, fi.IsDir())
 	}
 	if u.Username == "" {
 		t.Fatalf("didn't get a username")
diff --git a/libgo/go/patch/git.go b/libgo/go/patch/git.go
index 454eadececa..5c233fbaebf 100644
--- a/libgo/go/patch/git.go
+++ b/libgo/go/patch/git.go
@@ -22,7 +22,7 @@ func gitSHA1(data []byte) []byte {
 	h := sha1.New()
 	fmt.Fprintf(h, "blob %d\x00", len(data))
 	h.Write(data)
-	return h.Sum()
+	return h.Sum(nil)
 }
 
 // BUG(rsc): The Git binary delta format is not implemented, only Git binary literals.
diff --git a/libgo/go/path/filepath/match.go b/libgo/go/path/filepath/match.go
index 8cf1f9ad107..c3678f541d4 100644
--- a/libgo/go/path/filepath/match.go
+++ b/libgo/go/path/filepath/match.go
@@ -260,7 +260,7 @@ func glob(dir, pattern string, matches []string) (m []string, e error) {
 	if err != nil {
 		return
 	}
-	if !fi.IsDirectory() {
+	if !fi.IsDir() {
 		return
 	}
 	d, err := os.Open(dir)
diff --git a/libgo/go/path/filepath/path.go b/libgo/go/path/filepath/path.go
index 1b5d6c36495..e3d6c342ca6 100644
--- a/libgo/go/path/filepath/path.go
+++ b/libgo/go/path/filepath/path.go
@@ -223,7 +223,7 @@ func EvalSymlinks(path string) (string, error) {
 		if err != nil {
 			return "", err
 		}
-		if !fi.IsSymlink() {
+		if fi.Mode()&os.ModeSymlink == 0 {
 			b.WriteString(p)
 			if path != "" {
 				b.WriteRune(Separator)
@@ -312,7 +312,11 @@ func Rel(basepath, targpath string) (string, error) {
 	if b0 != bl {
 		// Base elements left. Must go up before going down.
 		seps := strings.Count(base[b0:bl], string(Separator))
-		buf := make([]byte, 3+seps*3+tl-t0)
+		size := 2 + seps*3
+		if tl != t0 {
+			size += 1 + tl - t0
+		}
+		buf := make([]byte, size)
 		n := copy(buf, "..")
 		for i := 0; i < seps; i++ {
 			buf[n] = Separator
@@ -341,19 +345,19 @@ var SkipDir = errors.New("skip this directory")
 // sole exception is that if path is a directory and the function returns the
 // special value SkipDir, the contents of the directory are skipped
 // and processing continues as usual on the next file.
-type WalkFunc func(path string, info *os.FileInfo, err error) error
+type WalkFunc func(path string, info os.FileInfo, err error) error
 
 // walk recursively descends path, calling w.
-func walk(path string, info *os.FileInfo, walkFn WalkFunc) error {
+func walk(path string, info os.FileInfo, walkFn WalkFunc) error {
 	err := walkFn(path, info, nil)
 	if err != nil {
-		if info.IsDirectory() && err == SkipDir {
+		if info.IsDir() && err == SkipDir {
 			return nil
 		}
 		return err
 	}
 
-	if !info.IsDirectory() {
+	if !info.IsDir() {
 		return nil
 	}
 
@@ -363,7 +367,7 @@ func walk(path string, info *os.FileInfo, walkFn WalkFunc) error {
 	}
 
 	for _, fileInfo := range list {
-		if err = walk(Join(path, fileInfo.Name), fileInfo, walkFn); err != nil {
+		if err = walk(Join(path, fileInfo.Name()), fileInfo, walkFn); err != nil {
 			return err
 		}
 	}
@@ -386,7 +390,7 @@ func Walk(root string, walkFn WalkFunc) error {
 // readDir reads the directory named by dirname and returns
 // a sorted list of directory entries.
 // Copied from io/ioutil to avoid the circular import.
-func readDir(dirname string) ([]*os.FileInfo, error) {
+func readDir(dirname string) ([]os.FileInfo, error) {
 	f, err := os.Open(dirname)
 	if err != nil {
 		return nil, err
@@ -396,20 +400,16 @@ func readDir(dirname string) ([]*os.FileInfo, error) {
 	if err != nil {
 		return nil, err
 	}
-	fi := make(fileInfoList, len(list))
-	for i := range list {
-		fi[i] = &list[i]
-	}
-	sort.Sort(fi)
-	return fi, nil
+	sort.Sort(byName(list))
+	return list, nil
 }
 
-// A dirList implements sort.Interface.
-type fileInfoList []*os.FileInfo
+// byName implements sort.Interface.
+type byName []os.FileInfo
 
-func (f fileInfoList) Len() int           { return len(f) }
-func (f fileInfoList) Less(i, j int) bool { return f[i].Name < f[j].Name }
-func (f fileInfoList) Swap(i, j int)      { f[i], f[j] = f[j], f[i] }
+func (f byName) Len() int           { return len(f) }
+func (f byName) Less(i, j int) bool { return f[i].Name() < f[j].Name() }
+func (f byName) Swap(i, j int)      { f[i], f[j] = f[j], f[i] }
 
 // Base returns the last element of path.
 // Trailing path separators are removed before extracting the last element.
diff --git a/libgo/go/path/filepath/path_test.go b/libgo/go/path/filepath/path_test.go
index c81cbf0ddc7..2bd62d34aeb 100644
--- a/libgo/go/path/filepath/path_test.go
+++ b/libgo/go/path/filepath/path_test.go
@@ -317,7 +317,7 @@ func checkMarks(t *testing.T, report bool) {
 // Assumes that each node name is unique. Good enough for a test.
 // If clear is true, any incoming error is cleared before return. The errors
 // are always accumulated, though.
-func mark(path string, info *os.FileInfo, err error, errors *[]error, clear bool) error {
+func mark(path string, info os.FileInfo, err error, errors *[]error, clear bool) error {
 	if err != nil {
 		*errors = append(*errors, err)
 		if clear {
@@ -325,8 +325,9 @@ func mark(path string, info *os.FileInfo, err error, errors *[]error, clear bool
 		}
 		return err
 	}
+	name := info.Name()
 	walkTree(tree, tree.name, func(path string, n *Node) {
-		if n.name == info.Name {
+		if n.name == name {
 			n.mark++
 		}
 	})
@@ -337,7 +338,7 @@ func TestWalk(t *testing.T) {
 	makeTree(t)
 	errors := make([]error, 0, 10)
 	clear := true
-	markFn := func(path string, info *os.FileInfo, err error) error {
+	markFn := func(path string, info os.FileInfo, err error) error {
 		return mark(path, info, err, &errors, clear)
 	}
 	// Expect no errors.
@@ -548,7 +549,7 @@ func TestEvalSymlinks(t *testing.T) {
 	// relative
 	testEvalSymlinks(t, tests)
 	// absolute
-/* These tests do not work in the gccgo test environment.
+	/* These tests do not work in the gccgo test environment.
 	goroot, err := filepath.EvalSymlinks(os.Getenv("GOROOT"))
 	if err != nil {
 		t.Fatalf("EvalSymlinks(%q) error: %v", os.Getenv("GOROOT"), err)
@@ -564,7 +565,7 @@ func TestEvalSymlinks(t *testing.T) {
 		}
 	}
 	testEvalSymlinks(t, tests)
-*/
+	*/
 }
 
 /* These tests do not work in the gccgo test environment.
@@ -603,7 +604,7 @@ func TestAbs(t *testing.T) {
 			t.Errorf("Abs(%q) error: %v", path, err)
 		}
 		absinfo, err := os.Stat(abspath)
-		if err != nil || absinfo.Ino != info.Ino {
+		if err != nil || !absinfo.(*os.FileStat).SameFile(info.(*os.FileStat)) {
 			t.Errorf("Abs(%q)=%q, not the same file", path, abspath)
 		}
 		if !filepath.IsAbs(abspath) {
@@ -634,6 +635,10 @@ var reltests = []RelTests{
 	{"a/b/../c", "a/b", "../b"},
 	{"a/b/c", "a/c/d", "../../c/d"},
 	{"a/b", "c/d", "../../c/d"},
+	{"a/b/c/d", "a/b", "../.."},
+	{"a/b/c/d", "a/b/", "../.."},
+	{"a/b/c/d/", "a/b", "../.."},
+	{"a/b/c/d/", "a/b/", "../.."},
 	{"../../a/b", "../../a/b/c/d", "c/d"},
 	{"/a/b", "/a/b", "."},
 	{"/a/b/.", "/a/b", "."},
@@ -645,6 +650,10 @@ var reltests = []RelTests{
 	{"/a/b/../c", "/a/b", "../b"},
 	{"/a/b/c", "/a/c/d", "../../c/d"},
 	{"/a/b", "/c/d", "../../c/d"},
+	{"/a/b/c/d", "/a/b", "../.."},
+	{"/a/b/c/d", "/a/b/", "../.."},
+	{"/a/b/c/d/", "/a/b", "../.."},
+	{"/a/b/c/d/", "/a/b/", "../.."},
 	{"/../../a/b", "/../../a/b/c/d", "c/d"},
 	{".", "a/b", "a/b"},
 	{".", "..", ".."},
diff --git a/libgo/go/strings/strings.go b/libgo/go/strings/strings.go
index b4d920714ac..53fdeadf97b 100644
--- a/libgo/go/strings/strings.go
+++ b/libgo/go/strings/strings.go
@@ -64,7 +64,17 @@ func Count(s, sep string) int {
 
 // Contains returns true if substr is within s.
 func Contains(s, substr string) bool {
-	return Index(s, substr) != -1
+	return Index(s, substr) >= 0
+}
+
+// ContainsAny returns true if any Unicode code points in chars are within s.
+func ContainsAny(s, chars string) bool {
+	return IndexAny(s, chars) >= 0
+}
+
+// ContainsRune returns true if the Unicode code point r is within s.
+func ContainsRune(s string, r rune) bool {
+	return IndexRune(s, r) >= 0
 }
 
 // Index returns the index of the first instance of sep in s, or -1 if sep is not present in s.
@@ -269,7 +279,7 @@ func FieldsFunc(s string, f func(rune) bool) []string {
 			fieldStart = i
 		}
 	}
-	if fieldStart != -1 { // Last field might end at EOF.
+	if fieldStart >= 0 { // Last field might end at EOF.
 		a[na] = s[fieldStart:]
 	}
 	return a
@@ -512,7 +522,7 @@ func lastIndexFunc(s string, f func(rune) bool, truth bool) int {
 }
 
 func makeCutsetFunc(cutset string) func(rune) bool {
-	return func(r rune) bool { return IndexRune(cutset, r) != -1 }
+	return func(r rune) bool { return IndexRune(cutset, r) >= 0 }
 }
 
 // Trim returns a slice of the string s with all leading and
diff --git a/libgo/go/strings/strings_test.go b/libgo/go/strings/strings_test.go
index 96207f5a2da..957af67b2ba 100644
--- a/libgo/go/strings/strings_test.go
+++ b/libgo/go/strings/strings_test.go
@@ -527,7 +527,7 @@ func TestTrim(t *testing.T) {
 		case "TrimRight":
 			f = TrimRight
 		default:
-			t.Error("Undefined trim function %s", name)
+			t.Errorf("Undefined trim function %s", name)
 		}
 		actual := f(tc.in, tc.cutset)
 		if actual != tc.out {
@@ -908,6 +908,56 @@ func TestContains(t *testing.T) {
 	}
 }
 
+var ContainsAnyTests = []struct {
+	str, substr string
+	expected    bool
+}{
+	{"", "", false},
+	{"", "a", false},
+	{"", "abc", false},
+	{"a", "", false},
+	{"a", "a", true},
+	{"aaa", "a", true},
+	{"abc", "xyz", false},
+	{"abc", "xcz", true},
+	{"a☺b☻c☹d", "uvw☻xyz", true},
+	{"aRegExp*", ".(|)*+?^$[]", true},
+	{dots + dots + dots, " ", false},
+}
+
+func TestContainsAny(t *testing.T) {
+	for _, ct := range ContainsAnyTests {
+		if ContainsAny(ct.str, ct.substr) != ct.expected {
+			t.Errorf("ContainsAny(%s, %s) = %v, want %v",
+				ct.str, ct.substr, !ct.expected, ct.expected)
+		}
+	}
+}
+
+var ContainsRuneTests = []struct {
+	str      string
+	r        rune
+	expected bool
+}{
+	{"", 'a', false},
+	{"a", 'a', true},
+	{"aaa", 'a', true},
+	{"abc", 'y', false},
+	{"abc", 'c', true},
+	{"a☺b☻c☹d", 'x', false},
+	{"a☺b☻c☹d", '☻', true},
+	{"aRegExp*", '*', true},
+}
+
+func TestContainsRune(t *testing.T) {
+	for _, ct := range ContainsRuneTests {
+		if ContainsRune(ct.str, ct.r) != ct.expected {
+			t.Errorf("ContainsRune(%s, %s) = %v, want %v",
+				ct.str, ct.r, !ct.expected, ct.expected)
+		}
+	}
+}
+
 var EqualFoldTests = []struct {
 	s, t string
 	out  bool
diff --git a/libgo/go/testing/benchmark.go b/libgo/go/testing/benchmark.go
index 4f049a31f75..e81e5c5845c 100644
--- a/libgo/go/testing/benchmark.go
+++ b/libgo/go/testing/benchmark.go
@@ -27,17 +27,19 @@ type InternalBenchmark struct {
 type B struct {
 	N         int
 	benchmark InternalBenchmark
-	ns        int64
+	ns        time.Duration
 	bytes     int64
-	start     int64
+	start     time.Time
+	timerOn   bool
 }
 
 // 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.start == 0 {
-		b.start = time.Nanoseconds()
+	if !b.timerOn {
+		b.start = time.Now()
+		b.timerOn = true
 	}
 }
 
@@ -45,17 +47,17 @@ func (b *B) StartTimer() {
 // while performing complex initialization that you don't
 // want to measure.
 func (b *B) StopTimer() {
-	if b.start > 0 {
-		b.ns += time.Nanoseconds() - b.start
+	if b.timerOn {
+		b.ns += time.Now().Sub(b.start)
+		b.timerOn = false
 	}
-	b.start = 0
 }
 
 // ResetTimer sets the elapsed benchmark time to zero.
 // It does not affect whether the timer is running.
 func (b *B) ResetTimer() {
-	if b.start > 0 {
-		b.start = time.Nanoseconds()
+	if b.timerOn {
+		b.start = time.Now()
 	}
 	b.ns = 0
 }
@@ -68,7 +70,7 @@ func (b *B) nsPerOp() int64 {
 	if b.N <= 0 {
 		return 0
 	}
-	return b.ns / int64(b.N)
+	return b.ns.Nanoseconds() / int64(b.N)
 }
 
 // runN runs a single benchmark for the specified number of iterations.
@@ -134,14 +136,14 @@ func (b *B) run() BenchmarkResult {
 	n := 1
 	b.runN(n)
 	// Run the benchmark for at least the specified amount of time.
-	time := int64(*benchTime * 1e9)
-	for b.ns < time && n < 1e9 {
+	d := time.Duration(*benchTime * float64(time.Second))
+	for b.ns < d && n < 1e9 {
 		last := n
 		// Predict iterations/sec.
 		if b.nsPerOp() == 0 {
 			n = 1e9
 		} else {
-			n = int(time / b.nsPerOp())
+			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.
@@ -156,23 +158,23 @@ func (b *B) run() BenchmarkResult {
 
 // The results of a benchmark run.
 type BenchmarkResult struct {
-	N     int   // The number of iterations.
-	Ns    int64 // The total time taken.
-	Bytes int64 // Bytes processed in one iteration.
+	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.Ns / int64(r.N)
+	return r.T.Nanoseconds() / int64(r.N)
 }
 
 func (r BenchmarkResult) mbPerSec() float64 {
-	if r.Bytes <= 0 || r.Ns <= 0 || r.N <= 0 {
+	if r.Bytes <= 0 || r.T <= 0 || r.N <= 0 {
 		return 0
 	}
-	return float64(r.Bytes) * float64(r.N) / float64(r.Ns) * 1e3
+	return (float64(r.Bytes) * float64(r.N) / 1e6) / r.T.Seconds()
 }
 
 func (r BenchmarkResult) String() string {
@@ -187,9 +189,9 @@ func (r BenchmarkResult) String() string {
 		// 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.Ns)/float64(r.N))
+			ns = fmt.Sprintf("%13.2f ns/op", float64(r.T.Nanoseconds())/float64(r.N))
 		} else {
-			ns = fmt.Sprintf("%12.1f ns/op", float64(r.Ns)/float64(r.N))
+			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)
diff --git a/libgo/go/testing/example.go b/libgo/go/testing/example.go
index 3b026ee66e0..e23f13b6f16 100644
--- a/libgo/go/testing/example.go
+++ b/libgo/go/testing/example.go
@@ -56,9 +56,9 @@ func RunExamples(examples []InternalExample) (ok bool) {
 		}()
 
 		// run example
-		ns := -time.Nanoseconds()
+		t0 := time.Now()
 		eg.F()
-		ns += time.Nanoseconds()
+		dt := time.Now().Sub(t0)
 
 		// close pipe, restore stdout/stderr, get output
 		w.Close()
@@ -66,7 +66,7 @@ func RunExamples(examples []InternalExample) (ok bool) {
 		out := <-outC
 
 		// report any errors
-		tstr := fmt.Sprintf("(%.2f seconds)", float64(ns)/1e9)
+		tstr := fmt.Sprintf("(%.2f seconds)", dt.Seconds())
 		if out != eg.Output {
 			fmt.Printf(
 				"--- FAIL: %s %s\ngot:\n%s\nwant:\n%s\n",
diff --git a/libgo/go/testing/testing.go b/libgo/go/testing/testing.go
index 08443a31259..0b3a07108cc 100644
--- a/libgo/go/testing/testing.go
+++ b/libgo/go/testing/testing.go
@@ -111,12 +111,13 @@ func decorate(s string, addFileLine bool) string {
 // T is a type passed to Test functions to manage test state and support formatted test logs.
 // Logs are accumulated during execution and dumped to standard error when done.
 type T struct {
-	name          string    // Name of test.
-	errors        string    // Error string from test.
-	failed        bool      // Test has failed.
-	ch            chan *T   // Output for serial tests.
-	startParallel chan bool // Parallel tests will wait on this.
-	ns            int64     // Duration of test in nanoseconds.
+	name          string        // Name of test.
+	errors        string        // Error string from test.
+	failed        bool          // Test has failed.
+	ch            chan *T       // Output for serial tests.
+	startParallel chan bool     // Parallel tests will wait on this.
+	start         time.Time     // Time test started
+	dt            time.Duration // Length of test
 }
 
 // Fail marks the Test function as having failed but continues execution.
@@ -128,7 +129,7 @@ func (t *T) Failed() bool { return t.failed }
 // FailNow marks the Test function as having failed and stops its execution.
 // Execution will continue at the next Test.
 func (t *T) FailNow() {
-	t.ns = time.Nanoseconds() - t.ns
+	t.dt = time.Now().Sub(t.start)
 	t.Fail()
 	t.ch <- t
 	runtime.Goexit()
@@ -184,9 +185,9 @@ type InternalTest struct {
 }
 
 func tRunner(t *T, test *InternalTest) {
-	t.ns = time.Nanoseconds()
+	t.start = time.Now()
 	test.F(t)
-	t.ns = time.Nanoseconds() - t.ns
+	t.dt = time.Now().Sub(t.start)
 	t.ch <- t
 }
 
@@ -211,7 +212,7 @@ func Main(matchString func(pat, str string) (bool, error), tests []InternalTest,
 }
 
 func report(t *T) {
-	tstr := fmt.Sprintf("(%.2f seconds)", float64(t.ns)/1e9)
+	tstr := fmt.Sprintf("(%.2f seconds)", t.dt.Seconds())
 	format := "--- %s: %s %s\n%s"
 	if t.failed {
 		fmt.Printf(format, "FAIL", t.name, tstr, t.errors)
diff --git a/libgo/go/text/template/doc.go b/libgo/go/text/template/doc.go
index 42f9e560be1..4208d53a0a4 100644
--- a/libgo/go/text/template/doc.go
+++ b/libgo/go/text/template/doc.go
@@ -18,8 +18,7 @@ The input text for a template is UTF-8-encoded text in any format.
 "{{" and "}}"; all text outside actions is copied to the output unchanged.
 Actions may not span newlines, although comments can.
 
-Once constructed, templates and template sets can be executed safely in
-parallel.
+Once constructed, a template may be executed safely in parallel.
 
 Actions
 
@@ -221,10 +220,9 @@ All produce the quoted word "output":
 
 Functions
 
-During execution functions are found in three function maps: first in the
-template, then in the "template set" (described below), and finally in the
-global function map. By default, no functions are defined in the template or
-the set but the Funcs methods can be used to add them.
+During execution functions are found in two function maps: first in the
+template, then in the global function map. By default, no functions are defined
+in the template but the Funcs methods can be used to add them.
 
 Predefined global functions are named as follows.
 
@@ -265,49 +263,63 @@ Predefined global functions are named as follows.
 The boolean functions take any zero value to be false and a non-zero value to
 be true.
 
-Template sets
+Associated templates
 
-Each template is named by a string specified when it is created.  A template may
-use a template invocation to instantiate another template directly or by its
-name; see the explanation of the template action above. The name is looked up
-in the template set associated with the template.
+Each template is named by a string specified when it is created. Also, each
+template is associated with zero or more other templates that it may invoke by
+name; such associations are transitive and form a name space of templates.
 
-If no template invocation actions occur in the template, the issue of template
-sets can be ignored.  If it does contain invocations, though, the template
-containing the invocations must be part of a template set in which to look up
-the names.
+A template may use a template invocation to instantiate another associated
+template; see the explanation of the "template" action above. The name must be
+that of a template associated with the template that contains the invocation.
 
-There are two ways to construct template sets.
+Nested template definitions
 
-The first is to use a Set's Parse method to create a set of named templates from
-a single input defining multiple templates.  The syntax of the definitions is to
-surround each template declaration with a define and end action.
+When parsing a template, another template may be defined and associated with the
+template being parsed. Template definitions must appear at the top level of the
+template, much like global variables in a Go program.
+
+The syntax of such definitions is to surround each template declaration with a
+"define" and "end" action.
 
 The define action names the template being created by providing a string
-constant. Here is a simple example of input to Set.Parse:
+constant. Here is a simple example:
 
-	`{{define "T1"}} definition of template T1 {{end}}
-	{{define "T2"}} definition of template T2 {{end}}
-	{{define "T3"}} {{template "T1"}} {{template "T2"}} {{end}}`
+	`{{define "T1"}}ONE{{end}}
+	{{define "T2"}}TWO{{end}}
+	{{define "T3"}}{{template "T1"}} {{template "T2"}}{{end}}
+	{{template "T3"}}`
 
 This defines two templates, T1 and T2, and a third T3 that invokes the other two
-when it is executed.
+when it is executed. Finally it invokes T3. If executed this template will
+produce the text
 
-The second way to build a template set is to use Set's Add method to add a
-parsed template to a set.  A template may be bound to at most one set.  If it's
-necessary to have a template in multiple sets, the template definition must be
-parsed multiple times to create distinct *Template values.
+	ONE TWO
 
-Set.Parse may be called multiple times on different inputs to construct the set.
-Two sets may therefore be constructed with a common base set of templates plus,
-through a second Parse call each, specializations for some elements.
+By construction, a template may reside in only one association. If it's
+necessary to have a template addressable from multiple associations, the
+template definition must be parsed multiple times to create distinct *Template
+values.
 
-A template may be executed directly or through Set.Execute, which executes a
-named template from the set.  To invoke our example above, we might write,
+Parse may be called multiple times to assemble the various associated templates;
+see the ParseFiles and ParseGlob functions and methods for simple ways to parse
+related templates stored in files.
 
-	err := set.Execute(os.Stdout, "T3", "no data needed")
+A template may be executed directly or through ExecuteTemplate, which executes
+an associated template identified by name. To invoke our example above, we
+might write,
+
+	err := tmpl.Execute(os.Stdout, "no data needed")
 	if err != nil {
 		log.Fatalf("execution failed: %s", err)
 	}
+
+or to invoke a particular template explicitly by name,
+
+	err := tmpl.ExecuteTemplate(os.Stdout, "T2", "no data needed")
+	if err != nil {
+		log.Fatalf("execution failed: %s", err)
+	}
+
 */
 package template
diff --git a/libgo/go/text/template/exec.go b/libgo/go/text/template/exec.go
index 19108825d58..b74bc3b01c9 100644
--- a/libgo/go/text/template/exec.go
+++ b/libgo/go/text/template/exec.go
@@ -85,8 +85,18 @@ func errRecover(errp *error) {
 	}
 }
 
+// ExecuteTemplate applies the template associated with t that has the given name
+// to the specified data object and writes the output to wr.
+func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error {
+	tmpl := t.tmpl[name]
+	if tmpl == nil {
+		return fmt.Errorf("template: no template %q associated with template %q", name, t.name)
+	}
+	return tmpl.Execute(wr, data)
+}
+
 // Execute applies a parsed template to the specified data object,
-// writing the output to wr.
+// and writes the output to wr.
 func (t *Template) Execute(wr io.Writer, data interface{}) (err error) {
 	defer errRecover(&err)
 	value := reflect.ValueOf(data)
@@ -251,13 +261,9 @@ func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) {
 }
 
 func (s *state) walkTemplate(dot reflect.Value, t *parse.TemplateNode) {
-	set := s.tmpl.set
-	if set == nil {
-		s.errorf("no set defined in which to invoke template named %q", t.Name)
-	}
-	tmpl := set.tmpl[t.Name]
+	tmpl := s.tmpl.tmpl[t.Name]
 	if tmpl == nil {
-		s.errorf("template %q not in set", t.Name)
+		s.errorf("template %q not defined", t.Name)
 	}
 	// Variables declared by the pipeline persist.
 	dot = s.evalPipeline(dot, t.Pipe)
@@ -376,7 +382,7 @@ func (s *state) evalFieldChain(dot, receiver reflect.Value, ident []string, args
 }
 
 func (s *state) evalFunction(dot reflect.Value, name string, args []parse.Node, final reflect.Value) reflect.Value {
-	function, ok := findFunction(name, s.tmpl, s.tmpl.set)
+	function, ok := findFunction(name, s.tmpl)
 	if !ok {
 		s.errorf("%q is not a defined function", name)
 	}
@@ -398,7 +404,7 @@ func (s *state) evalField(dot reflect.Value, fieldName string, args []parse.Node
 	if ptr.Kind() != reflect.Interface && ptr.CanAddr() {
 		ptr = ptr.Addr()
 	}
-	if method, ok := methodByName(ptr, fieldName); ok {
+	if method := ptr.MethodByName(fieldName); method.IsValid() {
 		return s.evalCall(dot, method, fieldName, args, final)
 	}
 	hasArgs := len(args) > 1 || final.IsValid()
@@ -433,17 +439,6 @@ func (s *state) evalField(dot reflect.Value, fieldName string, args []parse.Node
 	panic("not reached")
 }
 
-// TODO: delete when reflect's own MethodByName is released.
-func methodByName(receiver reflect.Value, name string) (reflect.Value, bool) {
-	typ := receiver.Type()
-	for i := 0; i < typ.NumMethod(); i++ {
-		if typ.Method(i).Name == name {
-			return receiver.Method(i), true // This value includes the receiver.
-		}
-	}
-	return zero, false
-}
-
 var (
 	errorType       = reflect.TypeOf((*error)(nil)).Elem()
 	fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
diff --git a/libgo/go/text/template/exec_test.go b/libgo/go/text/template/exec_test.go
index 67b9416cd76..cf3c4157281 100644
--- a/libgo/go/text/template/exec_test.go
+++ b/libgo/go/text/template/exec_test.go
@@ -476,7 +476,7 @@ func vfunc(V, *V) string {
 	return "vfunc"
 }
 
-func testExecute(execTests []execTest, set *Set, t *testing.T) {
+func testExecute(execTests []execTest, template *Template, t *testing.T) {
 	b := new(bytes.Buffer)
 	funcs := FuncMap{
 		"count":    count,
@@ -486,12 +486,13 @@ func testExecute(execTests []execTest, set *Set, t *testing.T) {
 		"zeroArgs": zeroArgs,
 	}
 	for _, test := range execTests {
-		tmpl := New(test.name).Funcs(funcs)
-		theSet := set
-		if theSet == nil {
-			theSet = new(Set)
+		var tmpl *Template
+		var err error
+		if template == nil {
+			tmpl, err = New(test.name).Funcs(funcs).Parse(test.input)
+		} else {
+			tmpl, err = template.New(test.name).Funcs(funcs).Parse(test.input)
 		}
-		_, err := tmpl.ParseInSet(test.input, theSet)
 		if err != nil {
 			t.Errorf("%s: parse error: %s", test.name, err)
 			continue
@@ -663,24 +664,34 @@ func TestTree(t *testing.T) {
 			},
 		},
 	}
-	set := new(Set)
-	_, err := set.Delims("(", ")").Parse(treeTemplate)
+	tmpl, err := New("root").Delims("(", ")").Parse(treeTemplate)
 	if err != nil {
 		t.Fatal("parse error:", err)
 	}
 	var b bytes.Buffer
-	err = set.Execute(&b, "tree", tree)
-	if err != nil {
-		t.Fatal("exec error:", err)
-	}
 	stripSpace := func(r rune) rune {
 		if r == '\t' || r == '\n' {
 			return -1
 		}
 		return r
 	}
-	result := strings.Map(stripSpace, b.String())
 	const expect = "[1[2[3[4]][5[6]]][7[8[9]][10[11]]]]"
+	// First by looking up the template.
+	err = tmpl.Lookup("tree").Execute(&b, tree)
+	if err != nil {
+		t.Fatal("exec error:", err)
+	}
+	result := strings.Map(stripSpace, b.String())
+	if result != expect {
+		t.Errorf("expected %q got %q", expect, result)
+	}
+	// Then direct to execution.
+	b.Reset()
+	err = tmpl.ExecuteTemplate(&b, "tree", tree)
+	if err != nil {
+		t.Fatal("exec error:", err)
+	}
+	result = strings.Map(stripSpace, b.String())
 	if result != expect {
 		t.Errorf("expected %q got %q", expect, result)
 	}
diff --git a/libgo/go/text/template/funcs.go b/libgo/go/text/template/funcs.go
index 2ca09a7c17f..d6e4bf1a216 100644
--- a/libgo/go/text/template/funcs.go
+++ b/libgo/go/text/template/funcs.go
@@ -17,8 +17,9 @@ import (
 
 // FuncMap is the type of the map defining the mapping from names to functions.
 // Each function must have either a single return value, or two return values of
-// which the second has type error. If the second argument evaluates to non-nil
-// during execution, execution terminates and Execute returns an error.
+// which the second has type error. In that case, if the second (error)
+// argument evaluates to non-nil during execution, execution terminates and
+// Execute returns that error.
 type FuncMap map[string]interface{}
 
 var builtins = FuncMap{
@@ -78,18 +79,13 @@ func goodFunc(typ reflect.Type) bool {
 	return false
 }
 
-// findFunction looks for a function in the template, set, and global map.
-func findFunction(name string, tmpl *Template, set *Set) (reflect.Value, bool) {
-	if tmpl != nil {
+// findFunction looks for a function in the template, and global map.
+func findFunction(name string, tmpl *Template) (reflect.Value, bool) {
+	if tmpl != nil && tmpl.common != nil {
 		if fn := tmpl.execFuncs[name]; fn.IsValid() {
 			return fn, true
 		}
 	}
-	if set != nil {
-		if fn := set.execFuncs[name]; fn.IsValid() {
-			return fn, true
-		}
-	}
 	if fn := builtinFuncs[name]; fn.IsValid() {
 		return fn, true
 	}
@@ -310,7 +306,6 @@ func JSEscape(w io.Writer, b []byte) {
 			if unicode.IsPrint(r) {
 				w.Write(b[i : i+size])
 			} else {
-				// TODO(dsymonds): Do this without fmt?
 				fmt.Fprintf(w, "\\u%04X", r)
 			}
 			i += size - 1
diff --git a/libgo/go/text/template/helper.go b/libgo/go/text/template/helper.go
index a743a8326ec..3636fb54d69 100644
--- a/libgo/go/text/template/helper.go
+++ b/libgo/go/text/template/helper.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Helper functions to make constructing templates and sets easier.
+// Helper functions to make constructing templates easier.
 
 package template
 
@@ -12,11 +12,11 @@ import (
 	"path/filepath"
 )
 
-// Functions and methods to parse a single template.
+// Functions and methods to parse templates.
 
 // Must is a helper that wraps a call to a function returning (*Template, error)
-// and panics if the error is non-nil. It is intended for use in variable initializations
-// such as
+// and panics if the error is non-nil. It is intended for use in variable
+// initializations such as
 //	var t = template.Must(template.New("name").Parse("text"))
 func Must(t *Template, err error) *Template {
 	if err != nil {
@@ -25,217 +25,84 @@ func Must(t *Template, err error) *Template {
 	return t
 }
 
-// ParseFile creates a new Template and parses the template definition from
-// the named file.  The template name is the base name of the file.
-func ParseFile(filename string) (*Template, error) {
-	t := New(filepath.Base(filename))
-	return t.ParseFile(filename)
+// ParseFiles creates a new Template and parses the template definitions from
+// the named files. The returned template's name will have the (base) name and
+// (parsed) contents of the first file. There must be at least one file.
+// If an error occurs, parsing stops and the returned *Template is nil.
+func ParseFiles(filenames ...string) (*Template, error) {
+	return parseFiles(nil, filenames...)
 }
 
-// parseFileInSet creates a new Template and parses the template
-// definition from the named file. The template name is the base name
-// of the file. It also adds the template to the set. Function bindings are
-// checked against those in the set.
-func parseFileInSet(filename string, set *Set) (*Template, error) {
-	t := New(filepath.Base(filename))
-	return t.parseFileInSet(filename, set)
+// ParseFiles parses the named files and associates the resulting templates with
+// t. If an error occurs, parsing stops and the returned template is nil;
+// otherwise it is t. There must be at least one file.
+func (t *Template) ParseFiles(filenames ...string) (*Template, error) {
+	return parseFiles(t, filenames...)
 }
 
-// ParseFile reads the template definition from a file and parses it to
-// construct an internal representation of the template for execution.
-// The returned template will be nil if an error occurs.
-func (t *Template) ParseFile(filename string) (*Template, error) {
-	b, err := ioutil.ReadFile(filename)
-	if err != nil {
-		return nil, err
+// parseFiles is the helper for the method and function. If the argument
+// template is nil, it is created from the first file.
+func parseFiles(t *Template, filenames ...string) (*Template, error) {
+	if len(filenames) == 0 {
+		// Not really a problem, but be consistent.
+		return nil, fmt.Errorf("template: no files named in call to ParseFiles")
 	}
-	return t.Parse(string(b))
-}
-
-// parseFileInSet is the same as ParseFile except that function bindings
-// are checked against those in the set and the template is added
-// to the set.
-// The returned template will be nil if an error occurs.
-func (t *Template) parseFileInSet(filename string, set *Set) (*Template, error) {
-	b, err := ioutil.ReadFile(filename)
-	if err != nil {
-		return nil, err
-	}
-	return t.ParseInSet(string(b), set)
-}
-
-// Functions and methods to parse a set.
-
-// SetMust is a helper that wraps a call to a function returning (*Set, error)
-// and panics if the error is non-nil. It is intended for use in variable initializations
-// such as
-//	var s = template.SetMust(template.ParseSetFiles("file"))
-func SetMust(s *Set, err error) *Set {
-	if err != nil {
-		panic(err)
-	}
-	return s
-}
-
-// ParseFiles parses the named files into a set of named templates.
-// Each file must be parseable by itself.
-// If an error occurs, parsing stops and the returned set is nil.
-func (s *Set) ParseFiles(filenames ...string) (*Set, error) {
 	for _, filename := range filenames {
 		b, err := ioutil.ReadFile(filename)
 		if err != nil {
 			return nil, err
 		}
-		_, err = s.Parse(string(b))
+		s := string(b)
+		name := filepath.Base(filename)
+		// First template becomes return value if not already defined,
+		// and we use that one for subsequent New calls to associate
+		// all the templates together. Also, if this file has the same name
+		// as t, this file becomes the contents of t, so
+		//  t, err := New(name).Funcs(xxx).ParseFiles(name)
+		// works. Otherwise we create a new template associated with t.
+		var tmpl *Template
+		if t == nil {
+			t = New(name)
+		}
+		if name == t.Name() {
+			tmpl = t
+		} else {
+			tmpl = t.New(name)
+		}
+		_, err = tmpl.Parse(s)
 		if err != nil {
 			return nil, err
 		}
 	}
-	return s, nil
+	return t, nil
 }
 
-// ParseSetFiles creates a new Set and parses the set definition from the
-// named files. Each file must be individually parseable.
-func ParseSetFiles(filenames ...string) (*Set, error) {
-	s := new(Set)
-	for _, filename := range filenames {
-		b, err := ioutil.ReadFile(filename)
-		if err != nil {
-			return nil, err
-		}
-		_, err = s.Parse(string(b))
-		if err != nil {
-			return nil, err
-		}
-	}
-	return s, nil
+// ParseGlob creates a new Template and parses the template definitions from the
+// files identified by the pattern, which must match at least one file. The
+// returned template will have the (base) name and (parsed) contents of the
+// first file matched by the pattern. ParseGlob is equivalent to calling
+// ParseFiles with the list of files matched by the pattern.
+func ParseGlob(pattern string) (*Template, error) {
+	return parseGlob(nil, pattern)
 }
 
-// ParseGlob parses the set definition from the files identified by the
-// pattern.  The pattern is processed by filepath.Glob and must match at
-// least one file.
-// If an error occurs, parsing stops and the returned set is nil.
-func (s *Set) ParseGlob(pattern string) (*Set, error) {
+// ParseGlob parses the template definitions in the files identified by the
+// pattern and associates the resulting templates with t. The pattern is
+// processed by filepath.Glob and must match at least one file. ParseGlob is
+// equivalent to calling t.ParseFiles with the list of files matched by the
+// pattern.
+func (t *Template) ParseGlob(pattern string) (*Template, error) {
+	return parseGlob(t, pattern)
+}
+
+// parseGlob is the implementation of the function and method ParseGlob.
+func parseGlob(t *Template, pattern string) (*Template, error) {
 	filenames, err := filepath.Glob(pattern)
 	if err != nil {
 		return nil, err
 	}
 	if len(filenames) == 0 {
-		return nil, fmt.Errorf("pattern matches no files: %#q", pattern)
+		return nil, fmt.Errorf("template: pattern matches no files: %#q", pattern)
 	}
-	return s.ParseFiles(filenames...)
-}
-
-// ParseSetGlob creates a new Set and parses the set definition from the
-// files identified by the pattern. The pattern is processed by filepath.Glob
-// and must match at least one file.
-func ParseSetGlob(pattern string) (*Set, error) {
-	set, err := new(Set).ParseGlob(pattern)
-	if err != nil {
-		return nil, err
-	}
-	return set, nil
-}
-
-// Functions and methods to parse stand-alone template files into a set.
-
-// ParseTemplateFiles parses the named template files and adds
-// them to the set. Each template will be named the base name of
-// its file.
-// Unlike with ParseFiles, each file should be a stand-alone template
-// definition suitable for Template.Parse (not Set.Parse); that is, the
-// file does not contain {{define}} clauses. ParseTemplateFiles is
-// therefore equivalent to calling the ParseFile function to create
-// individual templates, which are then added to the set.
-// Each file must be parseable by itself.
-// If an error occurs, parsing stops and the returned set is nil.
-func (s *Set) ParseTemplateFiles(filenames ...string) (*Set, error) {
-	for _, filename := range filenames {
-		_, err := parseFileInSet(filename, s)
-		if err != nil {
-			return nil, err
-		}
-	}
-	return s, nil
-}
-
-// ParseTemplateGlob parses the template files matched by the
-// patern and adds them to the set. Each template will be named
-// the base name of its file.
-// Unlike with ParseGlob, each file should be a stand-alone template
-// definition suitable for Template.Parse (not Set.Parse); that is, the
-// file does not contain {{define}} clauses. ParseTemplateGlob is
-// therefore equivalent to calling the ParseFile function to create
-// individual templates, which are then added to the set.
-// Each file must be parseable by itself.
-// If an error occurs, parsing stops and the returned set is nil.
-func (s *Set) ParseTemplateGlob(pattern string) (*Set, error) {
-	filenames, err := filepath.Glob(pattern)
-	if err != nil {
-		return nil, err
-	}
-	for _, filename := range filenames {
-		_, err := parseFileInSet(filename, s)
-		if err != nil {
-			return nil, err
-		}
-	}
-	return s, nil
-}
-
-// ParseTemplateFiles creates a set by parsing the named files,
-// each of which defines a single template. Each template will be
-// named the base name of its file.
-// Unlike with ParseFiles, each file should be a stand-alone template
-// definition suitable for Template.Parse (not Set.Parse); that is, the
-// file does not contain {{define}} clauses. ParseTemplateFiles is
-// therefore equivalent to calling the ParseFile function to create
-// individual templates, which are then added to the set.
-// Each file must be parseable by itself. Parsing stops if an error is
-// encountered.
-func ParseTemplateFiles(filenames ...string) (*Set, error) {
-	set := new(Set)
-	set.init()
-	for _, filename := range filenames {
-		t, err := ParseFile(filename)
-		if err != nil {
-			return nil, err
-		}
-		if err := set.add(t); err != nil {
-			return nil, err
-		}
-	}
-	return set, nil
-}
-
-// ParseTemplateGlob creates a set by parsing the files matched
-// by the pattern, each of which defines a single template. The pattern
-// is processed by filepath.Glob and must match at least one file. Each
-// template will be named the base name of its file.
-// Unlike with ParseGlob, each file should be a stand-alone template
-// definition suitable for Template.Parse (not Set.Parse); that is, the
-// file does not contain {{define}} clauses. ParseTemplateGlob is
-// therefore equivalent to calling the ParseFile function to create
-// individual templates, which are then added to the set.
-// Each file must be parseable by itself. Parsing stops if an error is
-// encountered.
-func ParseTemplateGlob(pattern string) (*Set, error) {
-	set := new(Set)
-	filenames, err := filepath.Glob(pattern)
-	if err != nil {
-		return nil, err
-	}
-	if len(filenames) == 0 {
-		return nil, fmt.Errorf("pattern matches no files: %#q", pattern)
-	}
-	for _, filename := range filenames {
-		t, err := ParseFile(filename)
-		if err != nil {
-			return nil, err
-		}
-		if err := set.add(t); err != nil {
-			return nil, err
-		}
-	}
-	return set, nil
+	return parseFiles(t, filenames...)
 }
diff --git a/libgo/go/text/template/multi_test.go b/libgo/go/text/template/multi_test.go
new file mode 100644
index 00000000000..7b35d2633d5
--- /dev/null
+++ b/libgo/go/text/template/multi_test.go
@@ -0,0 +1,288 @@
+// 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 template
+
+// Tests for mulitple-template parsing and execution.
+
+import (
+	"bytes"
+	"fmt"
+	"testing"
+	"text/template/parse"
+)
+
+type isEmptyTest struct {
+	name  string
+	input string
+	empty bool
+}
+
+var isEmptyTests = []isEmptyTest{
+	{"empty", ``, true},
+	{"nonempty", `hello`, false},
+	{"spaces only", " \t\n \t\n", true},
+	{"definition", `{{define "x"}}something{{end}}`, true},
+	{"definitions and space", "{{define `x`}}something{{end}}\n\n{{define `y`}}something{{end}}\n\n", true},
+	{"definitions and text", "{{define `x`}}something{{end}}\nx\n{{define `y`}}something{{end}}\ny\n}}", false},
+	{"definition and action", "{{define `x`}}something{{end}}{{if 3}}foo{{end}}", false},
+}
+
+func TestIsEmpty(t *testing.T) {
+	for _, test := range isEmptyTests {
+		template, err := New("root").Parse(test.input)
+		if err != nil {
+			t.Errorf("%q: unexpected error: %v", test.name, err)
+			continue
+		}
+		if empty := isEmpty(template.Root); empty != test.empty {
+			t.Errorf("%q: expected %t got %t", test.name, test.empty, empty)
+		}
+	}
+}
+
+const (
+	noError  = true
+	hasError = false
+)
+
+type multiParseTest struct {
+	name    string
+	input   string
+	ok      bool
+	names   []string
+	results []string
+}
+
+var multiParseTests = []multiParseTest{
+	{"empty", "", noError,
+		nil,
+		nil},
+	{"one", `{{define "foo"}} FOO {{end}}`, noError,
+		[]string{"foo"},
+		[]string{`[(text: " FOO ")]`}},
+	{"two", `{{define "foo"}} FOO {{end}}{{define "bar"}} BAR {{end}}`, noError,
+		[]string{"foo", "bar"},
+		[]string{`[(text: " FOO ")]`, `[(text: " BAR ")]`}},
+	// errors
+	{"missing end", `{{define "foo"}} FOO `, hasError,
+		nil,
+		nil},
+	{"malformed name", `{{define "foo}} FOO `, hasError,
+		nil,
+		nil},
+}
+
+func TestMultiParse(t *testing.T) {
+	for _, test := range multiParseTests {
+		template, err := New("root").Parse(test.input)
+		switch {
+		case err == nil && !test.ok:
+			t.Errorf("%q: expected error; got none", test.name)
+			continue
+		case err != nil && test.ok:
+			t.Errorf("%q: unexpected error: %v", test.name, err)
+			continue
+		case err != nil && !test.ok:
+			// expected error, got one
+			if *debug {
+				fmt.Printf("%s: %s\n\t%s\n", test.name, test.input, err)
+			}
+			continue
+		}
+		if template == nil {
+			continue
+		}
+		if len(template.tmpl) != len(test.names)+1 { // +1 for root
+			t.Errorf("%s: wrong number of templates; wanted %d got %d", test.name, len(test.names), len(template.tmpl))
+			continue
+		}
+		for i, name := range test.names {
+			tmpl, ok := template.tmpl[name]
+			if !ok {
+				t.Errorf("%s: can't find template %q", test.name, name)
+				continue
+			}
+			result := tmpl.Root.String()
+			if result != test.results[i] {
+				t.Errorf("%s=(%q): got\n\t%v\nexpected\n\t%v", test.name, test.input, result, test.results[i])
+			}
+		}
+	}
+}
+
+var multiExecTests = []execTest{
+	{"empty", "", "", nil, true},
+	{"text", "some text", "some text", nil, true},
+	{"invoke x", `{{template "x" .SI}}`, "TEXT", tVal, true},
+	{"invoke x no args", `{{template "x"}}`, "TEXT", tVal, true},
+	{"invoke dot int", `{{template "dot" .I}}`, "17", tVal, true},
+	{"invoke dot []int", `{{template "dot" .SI}}`, "[3 4 5]", tVal, true},
+	{"invoke dotV", `{{template "dotV" .U}}`, "v", tVal, true},
+	{"invoke nested int", `{{template "nested" .I}}`, "17", tVal, true},
+	{"variable declared by template", `{{template "nested" $x=.SI}},{{index $x 1}}`, "[3 4 5],4", tVal, true},
+
+	// User-defined function: test argument evaluator.
+	{"testFunc literal", `{{oneArg "joe"}}`, "oneArg=joe", tVal, true},
+	{"testFunc .", `{{oneArg .}}`, "oneArg=joe", "joe", true},
+}
+
+// These strings are also in testdata/*.
+const multiText1 = `
+	{{define "x"}}TEXT{{end}}
+	{{define "dotV"}}{{.V}}{{end}}
+`
+
+const multiText2 = `
+	{{define "dot"}}{{.}}{{end}}
+	{{define "nested"}}{{template "dot" .}}{{end}}
+`
+
+func TestMultiExecute(t *testing.T) {
+	// Declare a couple of templates first.
+	template, err := New("root").Parse(multiText1)
+	if err != nil {
+		t.Fatalf("parse error for 1: %s", err)
+	}
+	_, err = template.Parse(multiText2)
+	if err != nil {
+		t.Fatalf("parse error for 2: %s", err)
+	}
+	testExecute(multiExecTests, template, t)
+}
+
+func TestParseFiles(t *testing.T) {
+	_, err := ParseFiles("DOES NOT EXIST")
+	if err == nil {
+		t.Error("expected error for non-existent file; got none")
+	}
+	template := New("root")
+	_, err = template.ParseFiles("testdata/file1.tmpl", "testdata/file2.tmpl")
+	if err != nil {
+		t.Fatalf("error parsing files: %v", err)
+	}
+	testExecute(multiExecTests, template, t)
+}
+
+func TestParseGlob(t *testing.T) {
+	_, err := ParseGlob("DOES NOT EXIST")
+	if err == nil {
+		t.Error("expected error for non-existent file; got none")
+	}
+	_, err = New("error").ParseGlob("[x")
+	if err == nil {
+		t.Error("expected error for bad pattern; got none")
+	}
+	template := New("root")
+	_, err = template.ParseGlob("testdata/file*.tmpl")
+	if err != nil {
+		t.Fatalf("error parsing files: %v", err)
+	}
+	testExecute(multiExecTests, template, t)
+}
+
+// In these tests, actual content (not just template definitions) comes from the parsed files.
+
+var templateFileExecTests = []execTest{
+	{"test", `{{template "tmpl1.tmpl"}}{{template "tmpl2.tmpl"}}`, "template1\n\ny\ntemplate2\n\nx\n", 0, true},
+}
+
+func TestParseFilesWithData(t *testing.T) {
+	template, err := New("root").ParseFiles("testdata/tmpl1.tmpl", "testdata/tmpl2.tmpl")
+	if err != nil {
+		t.Fatalf("error parsing files: %v", err)
+	}
+	testExecute(templateFileExecTests, template, t)
+}
+
+func TestParseGlobWithData(t *testing.T) {
+	template, err := New("root").ParseGlob("testdata/tmpl*.tmpl")
+	if err != nil {
+		t.Fatalf("error parsing files: %v", err)
+	}
+	testExecute(templateFileExecTests, template, t)
+}
+
+const (
+	cloneText1 = `{{define "a"}}{{template "b"}}{{template "c"}}{{end}}`
+	cloneText2 = `{{define "b"}}b{{end}}`
+	cloneText3 = `{{define "c"}}root{{end}}`
+	cloneText4 = `{{define "c"}}clone{{end}}`
+)
+
+func TestClone(t *testing.T) {
+	// Create some templates and clone the root.
+	root, err := New("root").Parse(cloneText1)
+	if err != nil {
+		t.Fatal(err)
+	}
+	_, err = root.Parse(cloneText2)
+	if err != nil {
+		t.Fatal(err)
+	}
+	clone := root.Clone()
+	// Add variants to both.
+	_, err = root.Parse(cloneText3)
+	if err != nil {
+		t.Fatal(err)
+	}
+	_, err = clone.Parse(cloneText4)
+	if err != nil {
+		t.Fatal(err)
+	}
+	// Verify that the clone is self-consistent.
+	for k, v := range clone.tmpl {
+		if k == clone.name && v.tmpl[k] != clone {
+			t.Error("clone does not contain root")
+		}
+		if v != v.tmpl[v.name] {
+			t.Errorf("clone does not contain self for %q", k)
+		}
+	}
+	// Execute root.
+	var b bytes.Buffer
+	err = root.ExecuteTemplate(&b, "a", 0)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if b.String() != "broot" {
+		t.Errorf("expected %q got %q", "broot", b.String())
+	}
+	// Execute copy.
+	b.Reset()
+	err = clone.ExecuteTemplate(&b, "a", 0)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if b.String() != "bclone" {
+		t.Errorf("expected %q got %q", "bclone", b.String())
+	}
+}
+
+func TestAddParseTree(t *testing.T) {
+	// Create some templates.
+	root, err := New("root").Parse(cloneText1)
+	if err != nil {
+		t.Fatal(err)
+	}
+	_, err = root.Parse(cloneText2)
+	if err != nil {
+		t.Fatal(err)
+	}
+	// Add a new parse tree.
+	tree, err := parse.Parse("cloneText3", cloneText3, "", "", nil, builtins)
+	if err != nil {
+		t.Fatal(err)
+	}
+	added, err := root.AddParseTree("c", tree["c"])
+	// Execute.
+	var b bytes.Buffer
+	err = added.ExecuteTemplate(&b, "a", 0)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if b.String() != "broot" {
+		t.Errorf("expected %q got %q", "broot", b.String())
+	}
+}
diff --git a/libgo/go/text/template/parse.go b/libgo/go/text/template/parse.go
deleted file mode 100644
index 7075f2ac20e..00000000000
--- a/libgo/go/text/template/parse.go
+++ /dev/null
@@ -1,83 +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 template
-
-import (
-	"reflect"
-	"text/template/parse"
-)
-
-// Template is the representation of a parsed template.
-type Template struct {
-	name string
-	*parse.Tree
-	leftDelim  string
-	rightDelim string
-	// We use two maps, one for parsing and one for execution.
-	// This separation makes the API cleaner since it doesn't
-	// expose reflection to the client.
-	parseFuncs FuncMap
-	execFuncs  map[string]reflect.Value
-	set        *Set // can be nil.
-}
-
-// Name returns the name of the template.
-func (t *Template) Name() string {
-	return t.name
-}
-
-// Parsing.
-
-// New allocates a new template with the given name.
-func New(name string) *Template {
-	return &Template{
-		name:       name,
-		parseFuncs: make(FuncMap),
-		execFuncs:  make(map[string]reflect.Value),
-	}
-}
-
-// Delims sets the action delimiters, to be used in a subsequent
-// parse, to the specified strings.
-// An empty delimiter stands for the corresponding default: {{ or }}.
-// The return value is the template, so calls can be chained.
-func (t *Template) Delims(left, right string) *Template {
-	t.leftDelim = left
-	t.rightDelim = right
-	return t
-}
-
-// Funcs adds the elements of the argument map to the template's function
-// map.  It panics if a value in the map is not a function with appropriate
-// return type.
-// The return value is the template, so calls can be chained.
-func (t *Template) Funcs(funcMap FuncMap) *Template {
-	addValueFuncs(t.execFuncs, funcMap)
-	addFuncs(t.parseFuncs, funcMap)
-	return t
-}
-
-// Parse parses the template definition string to construct an internal
-// representation of the template for execution.
-func (t *Template) Parse(s string) (tmpl *Template, err error) {
-	t.Tree, err = parse.New(t.name).Parse(s, t.leftDelim, t.rightDelim, nil, t.parseFuncs, builtins)
-	if err != nil {
-		return nil, err
-	}
-	return t, nil
-}
-
-// ParseInSet parses the template definition string to construct an internal
-// representation of the template for execution. It also adds the template
-// to the set, which must not be nil. It is an error if s is already defined in the set.
-// Function bindings are checked against those in the set.
-func (t *Template) ParseInSet(s string, set *Set) (tmpl *Template, err error) {
-	t.Tree, err = parse.New(t.name).Parse(s, t.leftDelim, t.rightDelim, set.trees, t.parseFuncs, set.parseFuncs, builtins)
-	if err != nil {
-		return nil, err
-	}
-	err = set.add(t)
-	return t, err
-}
diff --git a/libgo/go/text/template/parse/parse.go b/libgo/go/text/template/parse/parse.go
index e906ee83aac..346f613b048 100644
--- a/libgo/go/text/template/parse/parse.go
+++ b/libgo/go/text/template/parse/parse.go
@@ -13,10 +13,10 @@ import (
 	"unicode"
 )
 
-// Tree is the representation of a parsed template.
+// Tree is the representation of a single parsed template.
 type Tree struct {
-	Name string    // Name is the name of the template.
-	Root *ListNode // Root is the top-level root of the parse tree.
+	Name string    // name of the template represented by the tree.
+	Root *ListNode // top-level root of the tree.
 	// Parsing only; cleared after parse.
 	funcs     []map[string]interface{}
 	lex       *lexer
@@ -25,6 +25,16 @@ type Tree struct {
 	vars      []string // variables defined at the moment.
 }
 
+// Parse returns a map from template name to parse.Tree, created by parsing the
+// templates described in the argument string. The top-level template will be
+// given the specified name. If an error is encountered, parsing stops and an
+// empty map is returned with the error.
+func Parse(name, text, leftDelim, rightDelim string, funcs ...map[string]interface{}) (treeSet map[string]*Tree, err error) {
+	treeSet = make(map[string]*Tree)
+	_, err = New(name).Parse(text, leftDelim, rightDelim, treeSet, funcs...)
+	return
+}
+
 // next returns the next token.
 func (t *Tree) next() item {
 	if t.peekCount > 0 {
@@ -58,7 +68,7 @@ func (t *Tree) peek() item {
 
 // Parsing.
 
-// New allocates a new template with the given name.
+// New allocates a new parse tree with the given name.
 func New(name string, funcs ...map[string]interface{}) *Tree {
 	return &Tree{
 		Name:  name,
@@ -87,6 +97,15 @@ func (t *Tree) expect(expected itemType, context string) item {
 	return token
 }
 
+// expectEither consumes the next token and guarantees it has one of the required types.
+func (t *Tree) expectOneOf(expected1, expected2 itemType, context string) item {
+	token := t.next()
+	if token.typ != expected1 && token.typ != expected2 {
+		t.errorf("expected %s or %s in %s; got %s", expected1, expected2, context, token)
+	}
+	return token
+}
+
 // unexpected complains about the token and terminates processing.
 func (t *Tree) unexpected(token item, context string) {
 	t.errorf("unexpected %s in %s", token, context)
@@ -107,7 +126,7 @@ func (t *Tree) recover(errp *error) {
 	return
 }
 
-// startParse starts the template parsing from the lexer.
+// startParse initializes the parser, using the lexer.
 func (t *Tree) startParse(funcs []map[string]interface{}, lex *lexer) {
 	t.Root = nil
 	t.lex = lex
@@ -143,17 +162,27 @@ func (t *Tree) atEOF() bool {
 	return false
 }
 
-// Parse parses the template definition string to construct an internal
-// representation of the template for execution. If either action delimiter
-// string is empty, the default ("{{" or "}}") is used.
+// Parse parses the template definition string to construct a representation of
+// the template for execution. If either action delimiter string is empty, the
+// default ("{{" or "}}") is used. Embedded template definitions are added to
+// the treeSet map.
 func (t *Tree) Parse(s, leftDelim, rightDelim string, treeSet map[string]*Tree, funcs ...map[string]interface{}) (tree *Tree, err error) {
 	defer t.recover(&err)
 	t.startParse(funcs, lex(t.Name, s, leftDelim, rightDelim))
 	t.parse(treeSet)
+	t.add(treeSet)
 	t.stopParse()
 	return t, nil
 }
 
+// add adds tree to the treeSet.
+func (t *Tree) add(treeSet map[string]*Tree) {
+	if _, present := treeSet[t.Name]; present {
+		t.errorf("template: multiple definition of template %q", t.Name)
+	}
+	treeSet[t.Name] = t
+}
+
 // parse is the top-level parser for a template, essentially the same
 // as itemList except it also parses {{define}} actions.
 // It runs to EOF.
@@ -163,7 +192,7 @@ func (t *Tree) parse(treeSet map[string]*Tree) (next Node) {
 		if t.peek().typ == itemLeftDelim {
 			delim := t.next()
 			if t.next().typ == itemDefine {
-				newT := New("new definition") // name will be updated once we know it.
+				newT := New("definition") // name will be updated once we know it.
 				newT.startParse(t.funcs, t.lex)
 				newT.parseDefinition(treeSet)
 				continue
@@ -183,11 +212,8 @@ func (t *Tree) parse(treeSet map[string]*Tree) (next Node) {
 // installs the definition in the treeSet map.  The "define" keyword has already
 // been scanned.
 func (t *Tree) parseDefinition(treeSet map[string]*Tree) {
-	if treeSet == nil {
-		t.errorf("no set specified for template definition")
-	}
 	const context = "define clause"
-	name := t.expect(itemString, context)
+	name := t.expectOneOf(itemString, itemRawString, context)
 	var err error
 	t.Name, err = strconv.Unquote(name.val)
 	if err != nil {
@@ -200,10 +226,7 @@ func (t *Tree) parseDefinition(treeSet map[string]*Tree) {
 		t.errorf("unexpected %s in %s", end, context)
 	}
 	t.stopParse()
-	if _, present := treeSet[t.Name]; present {
-		t.errorf("template: %q multiply defined", name)
-	}
-	treeSet[t.Name] = t
+	t.add(treeSet)
 }
 
 // itemList:
diff --git a/libgo/go/text/template/parse/parse_test.go b/libgo/go/text/template/parse/parse_test.go
index 5c10086cc7c..fc93455ecbc 100644
--- a/libgo/go/text/template/parse/parse_test.go
+++ b/libgo/go/text/template/parse/parse_test.go
@@ -236,7 +236,7 @@ var builtins = map[string]interface{}{
 
 func TestParse(t *testing.T) {
 	for _, test := range parseTests {
-		tmpl, err := New(test.name).Parse(test.input, "", "", nil, builtins)
+		tmpl, err := New(test.name).Parse(test.input, "", "", make(map[string]*Tree), builtins)
 		switch {
 		case err == nil && !test.ok:
 			t.Errorf("%q: expected error; got none", test.name)
diff --git a/libgo/go/text/template/parse/set.go b/libgo/go/text/template/parse/set.go
deleted file mode 100644
index 55f3ceb3d51..00000000000
--- a/libgo/go/text/template/parse/set.go
+++ /dev/null
@@ -1,15 +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 parse
-
-// Set returns a slice of Trees created by parsing the template set
-// definition in the argument string. If an error is encountered,
-// parsing stops and an empty slice is returned with the error.
-func Set(text, leftDelim, rightDelim string, funcs ...map[string]interface{}) (tree map[string]*Tree, err error) {
-	tree = make(map[string]*Tree)
-	// Top-level template name is needed but unused. TODO: clean this up.
-	_, err = New("ROOT").Parse(text, leftDelim, rightDelim, tree, funcs...)
-	return
-}
diff --git a/libgo/go/text/template/set.go b/libgo/go/text/template/set.go
deleted file mode 100644
index 48417044e77..00000000000
--- a/libgo/go/text/template/set.go
+++ /dev/null
@@ -1,121 +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 template
-
-import (
-	"fmt"
-	"io"
-	"reflect"
-	"text/template/parse"
-)
-
-// Set holds a set of related templates that can refer to one another by name.
-// The zero value represents an empty set.
-// A template may be a member of multiple sets.
-type Set struct {
-	tmpl       map[string]*Template
-	trees      map[string]*parse.Tree // maintained by parse package
-	leftDelim  string
-	rightDelim string
-	parseFuncs FuncMap
-	execFuncs  map[string]reflect.Value
-}
-
-func (s *Set) init() {
-	if s.tmpl == nil {
-		s.tmpl = make(map[string]*Template)
-		s.parseFuncs = make(FuncMap)
-		s.execFuncs = make(map[string]reflect.Value)
-	}
-}
-
-// Delims sets the action delimiters, to be used in a subsequent
-// parse, to the specified strings.
-// An empty delimiter stands for the corresponding default: {{ or }}.
-// The return value is the set, so calls can be chained.
-func (s *Set) Delims(left, right string) *Set {
-	s.leftDelim = left
-	s.rightDelim = right
-	return s
-}
-
-// Funcs adds the elements of the argument map to the set's function map.  It
-// panics if a value in the map is not a function with appropriate return
-// type.
-// The return value is the set, so calls can be chained.
-func (s *Set) Funcs(funcMap FuncMap) *Set {
-	s.init()
-	addValueFuncs(s.execFuncs, funcMap)
-	addFuncs(s.parseFuncs, funcMap)
-	return s
-}
-
-// Add adds the argument templates to the set. It panics if two templates
-// with the same name are added or if a template is already a member of
-// a set.
-// The return value is the set, so calls can be chained.
-func (s *Set) Add(templates ...*Template) *Set {
-	for _, t := range templates {
-		if err := s.add(t); err != nil {
-			panic(err)
-		}
-	}
-	return s
-}
-
-// add adds the argument template to the set.
-func (s *Set) add(t *Template) error {
-	s.init()
-	if t.set != nil {
-		return fmt.Errorf("template: %q already in a set", t.name)
-	}
-	if _, ok := s.tmpl[t.name]; ok {
-		return fmt.Errorf("template: %q already defined in set", t.name)
-	}
-	s.tmpl[t.name] = t
-	t.set = s
-	return nil
-}
-
-// Template returns the template with the given name in the set,
-// or nil if there is no such template.
-func (s *Set) Template(name string) *Template {
-	return s.tmpl[name]
-}
-
-// FuncMap returns the set's function map.
-func (s *Set) FuncMap() FuncMap {
-	return s.parseFuncs
-}
-
-// Execute applies the named template to the specified data object, writing
-// the output to wr.
-func (s *Set) Execute(wr io.Writer, name string, data interface{}) error {
-	tmpl := s.tmpl[name]
-	if tmpl == nil {
-		return fmt.Errorf("template: no template %q in set", name)
-	}
-	return tmpl.Execute(wr, data)
-}
-
-// Parse parses a string into a set of named templates.  Parse may be called
-// multiple times for a given set, adding the templates defined in the string
-// to the set.  It is an error if a template has a name already defined in the set.
-func (s *Set) Parse(text string) (*Set, error) {
-	trees, err := parse.Set(text, s.leftDelim, s.rightDelim, s.parseFuncs, builtins)
-	if err != nil {
-		return nil, err
-	}
-	s.init()
-	for name, tree := range trees {
-		tmpl := New(name)
-		tmpl.Tree = tree
-		err = s.add(tmpl)
-		if err != nil {
-			return s, err
-		}
-	}
-	return s, nil
-}
diff --git a/libgo/go/text/template/set_test.go b/libgo/go/text/template/set_test.go
deleted file mode 100644
index f437bc779c2..00000000000
--- a/libgo/go/text/template/set_test.go
+++ /dev/null
@@ -1,239 +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 template
-
-import (
-	"fmt"
-	"testing"
-)
-
-const (
-	noError  = true
-	hasError = false
-)
-
-type setParseTest struct {
-	name    string
-	input   string
-	ok      bool
-	names   []string
-	results []string
-}
-
-var setParseTests = []setParseTest{
-	{"empty", "", noError,
-		nil,
-		nil},
-	{"one", `{{define "foo"}} FOO {{end}}`, noError,
-		[]string{"foo"},
-		[]string{`[(text: " FOO ")]`}},
-	{"two", `{{define "foo"}} FOO {{end}}{{define "bar"}} BAR {{end}}`, noError,
-		[]string{"foo", "bar"},
-		[]string{`[(text: " FOO ")]`, `[(text: " BAR ")]`}},
-	// errors
-	{"missing end", `{{define "foo"}} FOO `, hasError,
-		nil,
-		nil},
-	{"malformed name", `{{define "foo}} FOO `, hasError,
-		nil,
-		nil},
-}
-
-func TestSetParse(t *testing.T) {
-	for _, test := range setParseTests {
-		set, err := new(Set).Parse(test.input)
-		switch {
-		case err == nil && !test.ok:
-			t.Errorf("%q: expected error; got none", test.name)
-			continue
-		case err != nil && test.ok:
-			t.Errorf("%q: unexpected error: %v", test.name, err)
-			continue
-		case err != nil && !test.ok:
-			// expected error, got one
-			if *debug {
-				fmt.Printf("%s: %s\n\t%s\n", test.name, test.input, err)
-			}
-			continue
-		}
-		if set == nil {
-			continue
-		}
-		if len(set.tmpl) != len(test.names) {
-			t.Errorf("%s: wrong number of templates; wanted %d got %d", test.name, len(test.names), len(set.tmpl))
-			continue
-		}
-		for i, name := range test.names {
-			tmpl, ok := set.tmpl[name]
-			if !ok {
-				t.Errorf("%s: can't find template %q", test.name, name)
-				continue
-			}
-			result := tmpl.Root.String()
-			if result != test.results[i] {
-				t.Errorf("%s=(%q): got\n\t%v\nexpected\n\t%v", test.name, test.input, result, test.results[i])
-			}
-		}
-	}
-}
-
-var setExecTests = []execTest{
-	{"empty", "", "", nil, true},
-	{"text", "some text", "some text", nil, true},
-	{"invoke x", `{{template "x" .SI}}`, "TEXT", tVal, true},
-	{"invoke x no args", `{{template "x"}}`, "TEXT", tVal, true},
-	{"invoke dot int", `{{template "dot" .I}}`, "17", tVal, true},
-	{"invoke dot []int", `{{template "dot" .SI}}`, "[3 4 5]", tVal, true},
-	{"invoke dotV", `{{template "dotV" .U}}`, "v", tVal, true},
-	{"invoke nested int", `{{template "nested" .I}}`, "17", tVal, true},
-	{"variable declared by template", `{{template "nested" $x=.SI}},{{index $x 1}}`, "[3 4 5],4", tVal, true},
-
-	// User-defined function: test argument evaluator.
-	{"testFunc literal", `{{oneArg "joe"}}`, "oneArg=joe", tVal, true},
-	{"testFunc .", `{{oneArg .}}`, "oneArg=joe", "joe", true},
-}
-
-// These strings are also in testdata/*.
-const setText1 = `
-	{{define "x"}}TEXT{{end}}
-	{{define "dotV"}}{{.V}}{{end}}
-`
-
-const setText2 = `
-	{{define "dot"}}{{.}}{{end}}
-	{{define "nested"}}{{template "dot" .}}{{end}}
-`
-
-func TestSetExecute(t *testing.T) {
-	// Declare a set with a couple of templates first.
-	set := new(Set)
-	_, err := set.Parse(setText1)
-	if err != nil {
-		t.Fatalf("error parsing set: %s", err)
-	}
-	_, err = set.Parse(setText2)
-	if err != nil {
-		t.Fatalf("error parsing set: %s", err)
-	}
-	testExecute(setExecTests, set, t)
-}
-
-func TestSetParseFiles(t *testing.T) {
-	set := new(Set)
-	_, err := set.ParseFiles("DOES NOT EXIST")
-	if err == nil {
-		t.Error("expected error for non-existent file; got none")
-	}
-	_, err = set.ParseFiles("testdata/file1.tmpl", "testdata/file2.tmpl")
-	if err != nil {
-		t.Fatalf("error parsing files: %v", err)
-	}
-	testExecute(setExecTests, set, t)
-}
-
-func TestParseSetFiles(t *testing.T) {
-	set := new(Set)
-	_, err := ParseSetFiles("DOES NOT EXIST")
-	if err == nil {
-		t.Error("expected error for non-existent file; got none")
-	}
-	set, err = ParseSetFiles("testdata/file1.tmpl", "testdata/file2.tmpl")
-	if err != nil {
-		t.Fatalf("error parsing files: %v", err)
-	}
-	testExecute(setExecTests, set, t)
-}
-
-func TestSetParseGlob(t *testing.T) {
-	_, err := new(Set).ParseGlob("DOES NOT EXIST")
-	if err == nil {
-		t.Error("expected error for non-existent file; got none")
-	}
-	_, err = new(Set).ParseGlob("[x")
-	if err == nil {
-		t.Error("expected error for bad pattern; got none")
-	}
-	set, err := new(Set).ParseGlob("testdata/file*.tmpl")
-	if err != nil {
-		t.Fatalf("error parsing files: %v", err)
-	}
-	testExecute(setExecTests, set, t)
-}
-
-func TestParseSetGlob(t *testing.T) {
-	_, err := ParseSetGlob("DOES NOT EXIST")
-	if err == nil {
-		t.Error("expected error for non-existent file; got none")
-	}
-	_, err = ParseSetGlob("[x")
-	if err == nil {
-		t.Error("expected error for bad pattern; got none")
-	}
-	set, err := ParseSetGlob("testdata/file*.tmpl")
-	if err != nil {
-		t.Fatalf("error parsing files: %v", err)
-	}
-	testExecute(setExecTests, set, t)
-}
-
-var templateFileExecTests = []execTest{
-	{"test", `{{template "tmpl1.tmpl"}}{{template "tmpl2.tmpl"}}`, "template1\ntemplate2\n", 0, true},
-}
-
-func TestSetParseTemplateFiles(t *testing.T) {
-	_, err := ParseTemplateFiles("DOES NOT EXIST")
-	if err == nil {
-		t.Error("expected error for non-existent file; got none")
-	}
-	set, err := new(Set).ParseTemplateFiles("testdata/tmpl1.tmpl", "testdata/tmpl2.tmpl")
-	if err != nil {
-		t.Fatalf("error parsing files: %v", err)
-	}
-	testExecute(templateFileExecTests, set, t)
-}
-
-func TestParseTemplateFiles(t *testing.T) {
-	_, err := ParseTemplateFiles("DOES NOT EXIST")
-	if err == nil {
-		t.Error("expected error for non-existent file; got none")
-	}
-	set, err := new(Set).ParseTemplateFiles("testdata/tmpl1.tmpl", "testdata/tmpl2.tmpl")
-	if err != nil {
-		t.Fatalf("error parsing files: %v", err)
-	}
-	testExecute(templateFileExecTests, set, t)
-}
-
-func TestSetParseTemplateGlob(t *testing.T) {
-	_, err := ParseTemplateGlob("DOES NOT EXIST")
-	if err == nil {
-		t.Error("expected error for non-existent file; got none")
-	}
-	_, err = new(Set).ParseTemplateGlob("[x")
-	if err == nil {
-		t.Error("expected error for bad pattern; got none")
-	}
-	set, err := new(Set).ParseTemplateGlob("testdata/tmpl*.tmpl")
-	if err != nil {
-		t.Fatalf("error parsing files: %v", err)
-	}
-	testExecute(templateFileExecTests, set, t)
-}
-
-func TestParseTemplateGlob(t *testing.T) {
-	_, err := ParseTemplateGlob("DOES NOT EXIST")
-	if err == nil {
-		t.Error("expected error for non-existent file; got none")
-	}
-	_, err = ParseTemplateGlob("[x")
-	if err == nil {
-		t.Error("expected error for bad pattern; got none")
-	}
-	set, err := ParseTemplateGlob("testdata/tmpl*.tmpl")
-	if err != nil {
-		t.Fatalf("error parsing files: %v", err)
-	}
-	testExecute(templateFileExecTests, set, t)
-}
diff --git a/libgo/go/text/template/template.go b/libgo/go/text/template/template.go
new file mode 100644
index 00000000000..04fca407c10
--- /dev/null
+++ b/libgo/go/text/template/template.go
@@ -0,0 +1,236 @@
+// 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 template
+
+import (
+	"bytes"
+	"fmt"
+	"reflect"
+	"text/template/parse"
+)
+
+// common holds the information shared by related templates.
+type common struct {
+	tmpl map[string]*Template
+	// We use two maps, one for parsing and one for execution.
+	// This separation makes the API cleaner since it doesn't
+	// expose reflection to the client.
+	parseFuncs FuncMap
+	execFuncs  map[string]reflect.Value
+}
+
+// Template is the representation of a parsed template. The *parse.Tree
+// field is exported only for use by html/template and should be treated
+// as unexported by all other clients.
+type Template struct {
+	name string
+	*parse.Tree
+	*common
+	leftDelim  string
+	rightDelim string
+}
+
+// New allocates a new template with the given name.
+func New(name string) *Template {
+	return &Template{
+		name: name,
+	}
+}
+
+// Name returns the name of the template.
+func (t *Template) Name() string {
+	return t.name
+}
+
+// New allocates a new template associated with the given one and with the same
+// delimiters. The association, which is transitive, allows one template to
+// invoke another with a {{template}} action.
+func (t *Template) New(name string) *Template {
+	t.init()
+	return &Template{
+		name:       name,
+		common:     t.common,
+		leftDelim:  t.leftDelim,
+		rightDelim: t.rightDelim,
+	}
+}
+
+func (t *Template) init() {
+	if t.common == nil {
+		t.common = new(common)
+		t.tmpl = make(map[string]*Template)
+		t.parseFuncs = make(FuncMap)
+		t.execFuncs = make(map[string]reflect.Value)
+	}
+}
+
+// Clone returns a duplicate of the template, including all associated
+// templates. The actual representation is not copied, but the name space of
+// associated templates is, so further calls to Parse in the copy will add
+// templates to the copy but not to the original. Clone can be used to prepare
+// common templates and use them with variant definitions for other templates by
+// adding the variants after the clone is made.
+func (t *Template) Clone() *Template {
+	nt := t.copy(nil)
+	nt.init()
+	nt.tmpl[t.name] = nt
+	for k, v := range t.tmpl {
+		if k == t.name { // Already installed.
+			continue
+		}
+		// The associated templates share nt's common structure.
+		tmpl := v.copy(nt.common)
+		nt.tmpl[k] = tmpl
+	}
+	for k, v := range t.parseFuncs {
+		nt.parseFuncs[k] = v
+	}
+	for k, v := range t.execFuncs {
+		nt.execFuncs[k] = v
+	}
+	return nt
+}
+
+// copy returns a shallow copy of t, with common set to the argument.
+func (t *Template) copy(c *common) *Template {
+	nt := New(t.name)
+	nt.Tree = t.Tree
+	nt.common = c
+	nt.leftDelim = t.leftDelim
+	nt.rightDelim = t.rightDelim
+	return nt
+}
+
+// AddParseTree creates a new template with the name and parse tree
+// and associates it with t.
+func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) {
+	if t.tmpl[name] != nil {
+		return nil, fmt.Errorf("template: redefinition of template %q", name)
+	}
+	nt := t.New(name)
+	nt.Tree = tree
+	t.tmpl[name] = nt
+	return nt, nil
+}
+
+// Templates returns a slice of the templates associated with t, including t
+// itself.
+func (t *Template) Templates() []*Template {
+	// Return a slice so we don't expose the map.
+	m := make([]*Template, 0, len(t.tmpl))
+	for _, v := range t.tmpl {
+		m = append(m, v)
+	}
+	return m
+}
+
+// Delims sets the action delimiters to the specified strings, to be used in
+// subsequent calls to Parse, ParseFiles, or ParseGlob. Nested template
+// definitions will inherit the settings. An empty delimiter stands for the
+// corresponding default: {{ or }}.
+// The return value is the template, so calls can be chained.
+func (t *Template) Delims(left, right string) *Template {
+	t.leftDelim = left
+	t.rightDelim = right
+	return t
+}
+
+// Funcs adds the elements of the argument map to the template's function map.
+// It panics if a value in the map is not a function with appropriate return
+// type. However, it is legal to overwrite elements of the map. The return
+// value is the template, so calls can be chained.
+func (t *Template) Funcs(funcMap FuncMap) *Template {
+	t.init()
+	addValueFuncs(t.execFuncs, funcMap)
+	addFuncs(t.parseFuncs, funcMap)
+	return t
+}
+
+// Lookup returns the template with the given name that is associated with t,
+// or nil if there is no such template.
+func (t *Template) Lookup(name string) *Template {
+	if t.common == nil {
+		return nil
+	}
+	return t.tmpl[name]
+}
+
+// Parse parses a string into a template. Nested template definitions will be
+// associated with the top-level template t. Parse may be called multiple times
+// to parse definitions of templates to associate with t. It is an error if a
+// resulting template is non-empty (contains content other than template
+// definitions) and would replace a non-empty template with the same name.
+// (In multiple calls to Parse with the same receiver template, only one call
+// can contain text other than space, comments, and template definitions.)
+func (t *Template) Parse(text string) (*Template, error) {
+	t.init()
+	trees, err := parse.Parse(t.name, text, t.leftDelim, t.rightDelim, t.parseFuncs, builtins)
+	if err != nil {
+		return nil, err
+	}
+	// Add the newly parsed trees, including the one for t, into our common structure.
+	for name, tree := range trees {
+		// If the name we parsed is the name of this template, overwrite this template.
+		// The associate method checks it's not a redefinition.
+		tmpl := t
+		if name != t.name {
+			tmpl = t.New(name)
+		}
+		// Even if t == tmpl, we need to install it in the common.tmpl map.
+		if err := t.associate(tmpl); err != nil {
+			return nil, err
+		}
+		tmpl.Tree = tree
+		tmpl.leftDelim = t.leftDelim
+		tmpl.rightDelim = t.rightDelim
+	}
+	return t, nil
+}
+
+// associate installs the new template into the group of templates associated
+// with t. It is an error to reuse a name except to overwrite an empty
+// template. The two are already known to share the common structure.
+func (t *Template) associate(new *Template) error {
+	if new.common != t.common {
+		panic("internal error: associate not common")
+	}
+	name := new.name
+	if old := t.tmpl[name]; old != nil {
+		oldIsEmpty := isEmpty(old.Root)
+		newIsEmpty := isEmpty(new.Root)
+		if !oldIsEmpty && !newIsEmpty {
+			return fmt.Errorf("template: redefinition of template %q", name)
+		}
+		if newIsEmpty {
+			// Whether old is empty or not, new is empty; no reason to replace old.
+			return nil
+		}
+	}
+	t.tmpl[name] = new
+	return nil
+}
+
+// isEmpty reports whether this tree (node) is empty of everything but space.
+func isEmpty(n parse.Node) bool {
+	switch n := n.(type) {
+	case *parse.ActionNode:
+	case *parse.IfNode:
+	case *parse.ListNode:
+		for _, node := range n.Nodes {
+			if !isEmpty(node) {
+				return false
+			}
+		}
+		return true
+	case *parse.RangeNode:
+	case *parse.TemplateNode:
+	case *parse.TextNode:
+		return len(bytes.TrimSpace(n.Text)) == 0
+	case *parse.WithNode:
+	default:
+		panic("unknown node: " + n.String())
+	}
+	return false
+}
diff --git a/libgo/go/text/template/testdata/tmpl1.tmpl b/libgo/go/text/template/testdata/tmpl1.tmpl
index 3d15b81735a..b72b3a340c7 100644
--- a/libgo/go/text/template/testdata/tmpl1.tmpl
+++ b/libgo/go/text/template/testdata/tmpl1.tmpl
@@ -1 +1,3 @@
 template1
+{{define "x"}}x{{end}}
+{{template "y"}}
diff --git a/libgo/go/text/template/testdata/tmpl2.tmpl b/libgo/go/text/template/testdata/tmpl2.tmpl
index a374d2fe7fc..16beba6e7dd 100644
--- a/libgo/go/text/template/testdata/tmpl2.tmpl
+++ b/libgo/go/text/template/testdata/tmpl2.tmpl
@@ -1 +1,3 @@
 template2
+{{define "y"}}y{{end}}
+{{template "x"}}
diff --git a/libgo/go/time/example_test.go b/libgo/go/time/example_test.go
new file mode 100644
index 00000000000..153b1a3b660
--- /dev/null
+++ b/libgo/go/time/example_test.go
@@ -0,0 +1,58 @@
+// 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 time_test
+
+import (
+	"fmt"
+	"time"
+)
+
+func expensiveCall() {}
+
+func ExampleDuration() {
+	t0 := time.Now()
+	expensiveCall()
+	t1 := time.Now()
+	fmt.Printf("The call took %v to run.\n", t1.Sub(t0))
+}
+
+var c chan int
+
+func handle(int) {}
+
+func ExampleAfter() {
+	select {
+	case m := <-c:
+		handle(m)
+	case <-time.After(5 * time.Minute):
+		fmt.Println("timed out")
+	}
+}
+
+func ExampleSleep() {
+	time.Sleep(100 * time.Millisecond)
+}
+
+func statusUpdate() string { return "" }
+
+func ExampleTick() {
+	c := time.Tick(1 * time.Minute)
+	for now := range c {
+		fmt.Printf("%v %s\n", now, statusUpdate())
+	}
+}
+
+func ExampleMonth() {
+	_, month, day := time.Now().Date()
+	if month == time.November && day == 10 {
+		fmt.Println("Happy Go day!")
+	}
+}
+
+// Go launched at Tue Nov 10 15:00:00 -0800 PST 2009
+func ExampleDate() {
+	t := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
+	fmt.Printf("Go launched at %s\n", t.Local())
+}
diff --git a/libgo/go/time/format.go b/libgo/go/time/format.go
index 14b712ad086..082a51a1621 100644
--- a/libgo/go/time/format.go
+++ b/libgo/go/time/format.go
@@ -1,10 +1,6 @@
 package time
 
-import (
-	"bytes"
-	"errors"
-	"strconv"
-)
+import "errors"
 
 const (
 	numeric = iota
@@ -259,8 +255,60 @@ func lookup(tab []string, val string) (int, string, error) {
 	return -1, val, errBad
 }
 
+// Duplicates functionality in strconv, but avoids dependency.
+func itoa(x int) string {
+	var buf [32]byte
+	n := len(buf)
+	if x == 0 {
+		return "0"
+	}
+	u := uint(x)
+	if x < 0 {
+		u = -u
+	}
+	for u > 0 {
+		n--
+		buf[n] = byte(u%10 + '0')
+		u /= 10
+	}
+	if x < 0 {
+		n--
+		buf[n] = '-'
+	}
+	return string(buf[n:])
+}
+
+// Never printed, just needs to be non-nil for return by atoi.
+var atoiError = errors.New("time: invalid number")
+
+// Duplicates functionality in strconv, but avoids dependency.
+func atoi(s string) (x int, err error) {
+	i := 0
+	if len(s) > 0 && s[0] == '-' {
+		i++
+	}
+	if i >= len(s) {
+		return 0, atoiError
+	}
+	for ; i < len(s); i++ {
+		c := s[i]
+		if c < '0' || c > '9' {
+			return 0, atoiError
+		}
+		if x >= (1<<31-10)/10 {
+			// will overflow
+			return 0, atoiError
+		}
+		x = x*10 + int(c) - '0'
+	}
+	if s[0] == '-' {
+		x = -x
+	}
+	return x, nil
+}
+
 func pad(i int, padding string) string {
-	s := strconv.Itoa(i)
+	s := itoa(i)
 	if i < 10 {
 		s = padding + s
 	}
@@ -273,7 +321,7 @@ func zeroPad(i int) string { return pad(i, "0") }
 func formatNano(nanosec, n int) string {
 	// User might give us bad data. Make sure it's positive and in range.
 	// They'll get nonsense output but it will have the right format.
-	s := strconv.Uitoa(uint(nanosec) % 1e9)
+	s := itoa(int(uint(nanosec) % 1e9))
 	// Zero pad left without fmt.
 	if len(s) < 9 {
 		s = "000000000"[:9-len(s)] + s
@@ -284,14 +332,42 @@ func formatNano(nanosec, n int) string {
 	return "." + s[:n]
 }
 
+// String returns the time formatted using the format string
+//	"Mon Jan _2 15:04:05 -0700 MST 2006"
+func (t Time) String() string {
+	return t.Format("Mon Jan _2 15:04:05 -0700 MST 2006")
+}
+
+type buffer []byte
+
+func (b *buffer) WriteString(s string) {
+	*b = append(*b, s...)
+}
+
+func (b *buffer) WriteByte(c byte) {
+	*b = append(*b, c)
+}
+
+func (b *buffer) String() string {
+	return string([]byte(*b))
+}
+
 // Format returns a textual representation of the time value formatted
 // according to layout.  The layout defines the format by showing the
 // representation of a standard time, which is then used to describe
 // the time to be formatted.  Predefined layouts ANSIC, UnixDate,
 // RFC3339 and others describe standard representations. For more
 // information about the formats, see the documentation for ANSIC.
-func (t *Time) Format(layout string) string {
-	b := new(bytes.Buffer)
+func (t Time) Format(layout string) string {
+	var (
+		year  int = -1
+		month Month
+		day   int
+		hour  int = -1
+		min   int
+		sec   int
+		b     buffer
+	)
 	// Each iteration generates one std value.
 	for {
 		prefix, std, suffix := nextStdChunk(layout)
@@ -299,62 +375,92 @@ func (t *Time) Format(layout string) string {
 		if std == "" {
 			break
 		}
+
+		// Compute year, month, day if needed.
+		if year < 0 {
+			// Jan 01 02 2006
+			if a, z := std[0], std[len(std)-1]; a == 'J' || a == 'j' || z == '1' || z == '2' || z == '6' {
+				year, month, day = t.Date()
+			}
+		}
+
+		// Compute hour, minute, second if needed.
+		if hour < 0 {
+			// 03 04 05 15 pm
+			if z := std[len(std)-1]; z == '3' || z == '4' || z == '5' || z == 'm' || z == 'M' {
+				hour, min, sec = t.Clock()
+			}
+		}
+
 		var p string
 		switch std {
 		case stdYear:
-			p = zeroPad(int(t.Year % 100))
+			p = zeroPad(year % 100)
 		case stdLongYear:
-			p = strconv.Itoa64(t.Year)
+			p = itoa(year)
 		case stdMonth:
-			p = shortMonthNames[t.Month]
+			p = month.String()[:3]
 		case stdLongMonth:
-			p = longMonthNames[t.Month]
+			p = month.String()
 		case stdNumMonth:
-			p = strconv.Itoa(t.Month)
+			p = itoa(int(month))
 		case stdZeroMonth:
-			p = zeroPad(t.Month)
+			p = zeroPad(int(month))
 		case stdWeekDay:
-			p = shortDayNames[t.Weekday()]
+			p = t.Weekday().String()[:3]
 		case stdLongWeekDay:
-			p = longDayNames[t.Weekday()]
+			p = t.Weekday().String()
 		case stdDay:
-			p = strconv.Itoa(t.Day)
+			p = itoa(day)
 		case stdUnderDay:
-			p = pad(t.Day, " ")
+			p = pad(day, " ")
 		case stdZeroDay:
-			p = zeroPad(t.Day)
+			p = zeroPad(day)
 		case stdHour:
-			p = zeroPad(t.Hour)
+			p = zeroPad(hour)
 		case stdHour12:
 			// Noon is 12PM, midnight is 12AM.
-			hr := t.Hour % 12
+			hr := hour % 12
 			if hr == 0 {
 				hr = 12
 			}
-			p = strconv.Itoa(hr)
+			p = itoa(hr)
 		case stdZeroHour12:
 			// Noon is 12PM, midnight is 12AM.
-			hr := t.Hour % 12
+			hr := hour % 12
 			if hr == 0 {
 				hr = 12
 			}
 			p = zeroPad(hr)
 		case stdMinute:
-			p = strconv.Itoa(t.Minute)
+			p = itoa(min)
 		case stdZeroMinute:
-			p = zeroPad(t.Minute)
+			p = zeroPad(min)
 		case stdSecond:
-			p = strconv.Itoa(t.Second)
+			p = itoa(sec)
 		case stdZeroSecond:
-			p = zeroPad(t.Second)
+			p = zeroPad(sec)
+		case stdPM:
+			if hour >= 12 {
+				p = "PM"
+			} else {
+				p = "AM"
+			}
+		case stdpm:
+			if hour >= 12 {
+				p = "pm"
+			} else {
+				p = "am"
+			}
 		case stdISO8601TZ, stdISO8601ColonTZ, stdNumTZ, stdNumColonTZ:
 			// Ugly special case.  We cheat and take the "Z" variants
 			// to mean "the time zone as formatted for ISO 8601".
-			if t.ZoneOffset == 0 && std[0] == 'Z' {
+			_, offset := t.Zone()
+			if offset == 0 && std[0] == 'Z' {
 				p = "Z"
 				break
 			}
-			zone := t.ZoneOffset / 60 // convert to minutes
+			zone := offset / 60 // convert to minutes
 			if zone < 0 {
 				p = "-"
 				zone = -zone
@@ -366,25 +472,14 @@ func (t *Time) Format(layout string) string {
 				p += ":"
 			}
 			p += zeroPad(zone % 60)
-		case stdPM:
-			if t.Hour >= 12 {
-				p = "PM"
-			} else {
-				p = "AM"
-			}
-		case stdpm:
-			if t.Hour >= 12 {
-				p = "pm"
-			} else {
-				p = "am"
-			}
 		case stdTZ:
-			if t.Zone != "" {
-				p = t.Zone
+			name, offset := t.Zone()
+			if name != "" {
+				p = name
 			} else {
 				// No time zone known for this time, but we must print one.
 				// Use the -0700 format.
-				zone := t.ZoneOffset / 60 // convert to minutes
+				zone := offset / 60 // convert to minutes
 				if zone < 0 {
 					p = "-"
 					zone = -zone
@@ -396,7 +491,7 @@ func (t *Time) Format(layout string) string {
 			}
 		default:
 			if len(std) >= 2 && std[0:2] == ".0" {
-				p = formatNano(t.Nanosecond, len(std)-1)
+				p = formatNano(t.Nanosecond(), len(std)-1)
 			}
 		}
 		b.WriteString(p)
@@ -405,14 +500,6 @@ func (t *Time) Format(layout string) string {
 	return b.String()
 }
 
-// String returns a Unix-style representation of the time value.
-func (t *Time) String() string {
-	if t == nil {
-		return "<nil>"
-	}
-	return t.Format(UnixDate)
-}
-
 var errBad = errors.New("bad value for field") // placeholder not passed to user
 
 // ParseError describes a problem parsing a time string.
@@ -424,17 +511,21 @@ type ParseError struct {
 	Message    string
 }
 
-// String is the string representation of a ParseError.
+func quote(s string) string {
+	return "\"" + s + "\""
+}
+
+// Error returns the string representation of a ParseError.
 func (e *ParseError) Error() string {
 	if e.Message == "" {
 		return "parsing time " +
-			strconv.Quote(e.Value) + " as " +
-			strconv.Quote(e.Layout) + ": cannot parse " +
-			strconv.Quote(e.ValueElem) + " as " +
-			strconv.Quote(e.LayoutElem)
+			quote(e.Value) + " as " +
+			quote(e.Layout) + ": cannot parse " +
+			quote(e.ValueElem) + " as " +
+			quote(e.LayoutElem)
 	}
 	return "parsing time " +
-		strconv.Quote(e.Value) + e.Message
+		quote(e.Value) + e.Message
 }
 
 // isDigit returns true if s[i] is a decimal digit, false if not or
@@ -498,30 +589,42 @@ func skip(value, prefix string) (string, error) {
 // representations.For more information about the formats, see the
 // documentation for ANSIC.
 //
-// Only those elements present in the value will be set in the returned time
-// structure.  Also, if the input string represents an inconsistent time
-// (such as having the wrong day of the week), the returned value will also
-// be inconsistent.  In any case, the elements of the returned time will be
-// sane: hours in 0..23, minutes in 0..59, day of month in 1..31, etc.
+// Elements omitted from the value are assumed to be zero, or when
+// zero is impossible, one, so parsing "3:04pm" returns the time
+// corresponding to Jan 1, year 0, 15:04:00 UTC.
 // Years must be in the range 0000..9999. The day of the week is checked
 // for syntax but it is otherwise ignored.
-func Parse(alayout, avalue string) (*Time, error) {
-	var t Time
+func Parse(layout, value string) (Time, error) {
+	alayout, avalue := layout, value
 	rangeErrString := "" // set if a value is out of range
 	amSet := false       // do we need to subtract 12 from the hour for midnight?
 	pmSet := false       // do we need to add 12 to the hour?
-	layout, value := alayout, avalue
+
+	// Time being constructed.
+	var (
+		year       int
+		month      int = 1 // January
+		day        int = 1
+		hour       int
+		min        int
+		sec        int
+		nsec       int
+		z          *Location
+		zoneOffset int = -1
+		zoneName   string
+	)
+
 	// Each iteration processes one std value.
 	for {
 		var err error
 		prefix, std, suffix := nextStdChunk(layout)
 		value, err = skip(value, prefix)
 		if err != nil {
-			return nil, &ParseError{alayout, avalue, prefix, value, ""}
+			return Time{}, &ParseError{alayout, avalue, prefix, value, ""}
 		}
 		if len(std) == 0 {
 			if len(value) != 0 {
-				return nil, &ParseError{alayout, avalue, "", value, ": extra text: " + value}
+				return Time{}, &ParseError{alayout, avalue, "", value, ": extra text: " + value}
 			}
 			break
 		}
@@ -534,11 +637,11 @@ func Parse(alayout, avalue string) (*Time, error) {
 				break
 			}
 			p, value = value[0:2], value[2:]
-			t.Year, err = strconv.Atoi64(p)
-			if t.Year >= 69 { // Unix time starts Dec 31 1969 in some time zones
-				t.Year += 1900
+			year, err = atoi(p)
+			if year >= 69 { // Unix time starts Dec 31 1969 in some time zones
+				year += 1900
 			} else {
-				t.Year += 2000
+				year += 2000
 			}
 		case stdLongYear:
 			if len(value) < 4 || !isDigit(value, 0) {
@@ -546,14 +649,14 @@ func Parse(alayout, avalue string) (*Time, error) {
 				break
 			}
 			p, value = value[0:4], value[4:]
-			t.Year, err = strconv.Atoi64(p)
+			year, err = atoi(p)
 		case stdMonth:
-			t.Month, value, err = lookup(shortMonthNames, value)
+			month, value, err = lookup(shortMonthNames, value)
 		case stdLongMonth:
-			t.Month, value, err = lookup(longMonthNames, value)
+			month, value, err = lookup(longMonthNames, value)
 		case stdNumMonth, stdZeroMonth:
-			t.Month, value, err = getnum(value, std == stdZeroMonth)
-			if t.Month <= 0 || 12 < t.Month {
+			month, value, err = getnum(value, std == stdZeroMonth)
+			if month <= 0 || 12 < month {
 				rangeErrString = "month"
 			}
 		case stdWeekDay:
@@ -565,29 +668,28 @@ func Parse(alayout, avalue string) (*Time, error) {
 			if std == stdUnderDay && len(value) > 0 && value[0] == ' ' {
 				value = value[1:]
 			}
-			t.Day, value, err = getnum(value, std == stdZeroDay)
-			if t.Day < 0 || 31 < t.Day {
-				// TODO: be more thorough in date check?
+			day, value, err = getnum(value, std == stdZeroDay)
+			if day < 0 || 31 < day {
 				rangeErrString = "day"
 			}
 		case stdHour:
-			t.Hour, value, err = getnum(value, false)
-			if t.Hour < 0 || 24 <= t.Hour {
+			hour, value, err = getnum(value, false)
+			if hour < 0 || 24 <= hour {
 				rangeErrString = "hour"
 			}
 		case stdHour12, stdZeroHour12:
-			t.Hour, value, err = getnum(value, std == stdZeroHour12)
-			if t.Hour < 0 || 12 < t.Hour {
+			hour, value, err = getnum(value, std == stdZeroHour12)
+			if hour < 0 || 12 < hour {
 				rangeErrString = "hour"
 			}
 		case stdMinute, stdZeroMinute:
-			t.Minute, value, err = getnum(value, std == stdZeroMinute)
-			if t.Minute < 0 || 60 <= t.Minute {
+			min, value, err = getnum(value, std == stdZeroMinute)
+			if min < 0 || 60 <= min {
 				rangeErrString = "minute"
 			}
 		case stdSecond, stdZeroSecond:
-			t.Second, value, err = getnum(value, std == stdZeroSecond)
-			if t.Second < 0 || 60 <= t.Second {
+			sec, value, err = getnum(value, std == stdZeroSecond)
+			if sec < 0 || 60 <= sec {
 				rangeErrString = "second"
 			}
 			// Special case: do we have a fractional second but no
@@ -602,52 +704,9 @@ func Parse(alayout, avalue string) (*Time, error) {
 				n := 2
 				for ; n < len(value) && isDigit(value, n); n++ {
 				}
-				rangeErrString, err = t.parseNanoseconds(value, n)
+				nsec, rangeErrString, err = parseNanoseconds(value, n)
 				value = value[n:]
 			}
-		case stdISO8601TZ, stdISO8601ColonTZ, stdNumTZ, stdNumShortTZ, stdNumColonTZ:
-			if std[0] == 'Z' && len(value) >= 1 && value[0] == 'Z' {
-				value = value[1:]
-				t.Zone = "UTC"
-				break
-			}
-			var sign, hh, mm string
-			if std == stdISO8601ColonTZ || std == stdNumColonTZ {
-				if len(value) < 6 {
-					err = errBad
-					break
-				}
-				if value[3] != ':' {
-					err = errBad
-					break
-				}
-				sign, hh, mm, value = value[0:1], value[1:3], value[4:6], value[6:]
-			} else if std == stdNumShortTZ {
-				if len(value) < 3 {
-					err = errBad
-					break
-				}
-				sign, hh, mm, value = value[0:1], value[1:3], "00", value[3:]
-			} else {
-				if len(value) < 5 {
-					err = errBad
-					break
-				}
-				sign, hh, mm, value = value[0:1], value[1:3], value[3:5], value[5:]
-			}
-			var hr, min int
-			hr, err = strconv.Atoi(hh)
-			if err == nil {
-				min, err = strconv.Atoi(mm)
-			}
-			t.ZoneOffset = (hr*60 + min) * 60 // offset is in seconds
-			switch sign[0] {
-			case '+':
-			case '-':
-				t.ZoneOffset = -t.ZoneOffset
-			default:
-				err = errBad
-			}
 		case stdPM:
 			if len(value) < 2 {
 				err = errBad
@@ -676,10 +735,54 @@ func Parse(alayout, avalue string) (*Time, error) {
 			default:
 				err = errBad
 			}
+		case stdISO8601TZ, stdISO8601ColonTZ, stdNumTZ, stdNumShortTZ, stdNumColonTZ:
+			if std[0] == 'Z' && len(value) >= 1 && value[0] == 'Z' {
+				value = value[1:]
+				z = UTC
+				break
+			}
+			var sign, hour, min string
+			if std == stdISO8601ColonTZ || std == stdNumColonTZ {
+				if len(value) < 6 {
+					err = errBad
+					break
+				}
+				if value[3] != ':' {
+					err = errBad
+					break
+				}
+				sign, hour, min, value = value[0:1], value[1:3], value[4:6], value[6:]
+			} else if std == stdNumShortTZ {
+				if len(value) < 3 {
+					err = errBad
+					break
+				}
+				sign, hour, min, value = value[0:1], value[1:3], "00", value[3:]
+			} else {
+				if len(value) < 5 {
+					err = errBad
+					break
+				}
+				sign, hour, min, value = value[0:1], value[1:3], value[3:5], value[5:]
+			}
+			var hr, mm int
+			hr, err = atoi(hour)
+			if err == nil {
+				mm, err = atoi(min)
+			}
+			zoneOffset = (hr*60 + mm) * 60 // offset is in seconds
+			switch sign[0] {
+			case '+':
+			case '-':
+				zoneOffset = -zoneOffset
+			default:
+				err = errBad
+			}
 		case stdTZ:
 			// Does it look like a time zone?
 			if len(value) >= 3 && value[0:3] == "UTC" {
-				t.Zone, value = value[0:3], value[3:]
+				z = UTC
+				value = value[3:]
 				break
 			}
 
@@ -700,47 +803,86 @@ func Parse(alayout, avalue string) (*Time, error) {
 				break
 			}
 			// It's a valid format.
-			t.Zone = p
-			// Can we find its offset?
-			if offset, found := lookupByName(p); found {
-				t.ZoneOffset = offset
-			}
+			zoneName = p
 		default:
 			if len(value) < len(std) {
 				err = errBad
 				break
 			}
 			if len(std) >= 2 && std[0:2] == ".0" {
-				rangeErrString, err = t.parseNanoseconds(value, len(std))
+				nsec, rangeErrString, err = parseNanoseconds(value, len(std))
 				value = value[len(std):]
 			}
 		}
 		if rangeErrString != "" {
-			return nil, &ParseError{alayout, avalue, std, value, ": " + rangeErrString + " out of range"}
+			return Time{}, &ParseError{alayout, avalue, std, value, ": " + rangeErrString + " out of range"}
 		}
 		if err != nil {
-			return nil, &ParseError{alayout, avalue, std, value, ""}
+			return Time{}, &ParseError{alayout, avalue, std, value, ""}
 		}
 	}
-	if pmSet && t.Hour < 12 {
-		t.Hour += 12
-	} else if amSet && t.Hour == 12 {
-		t.Hour = 0
+	if pmSet && hour < 12 {
+		hour += 12
+	} else if amSet && hour == 12 {
+		hour = 0
 	}
-	return &t, nil
+
+	// TODO: be more aggressive checking day?
+	if z != nil {
+		return Date(year, Month(month), day, hour, min, sec, nsec, z), nil
+	}
+
+	t := Date(year, Month(month), day, hour, min, sec, nsec, UTC)
+	if zoneOffset != -1 {
+		t.sec -= int64(zoneOffset)
+
+		// Look for local zone with the given offset.
+		// If that zone was in effect at the given time, use it.
+		name, offset, _, _, _ := Local.lookup(t.sec + internalToUnix)
+		if offset == zoneOffset && (zoneName == "" || name == zoneName) {
+			t.loc = Local
+			return t, nil
+		}
+
+		// Otherwise create fake zone to record offset.
+		t.loc = FixedZone(zoneName, zoneOffset)
+		return t, nil
+	}
+
+	if zoneName != "" {
+		// Look for local zone with the given offset.
+		// If that zone was in effect at the given time, use it.
+		offset, _, ok := Local.lookupName(zoneName)
+		if ok {
+			name, off, _, _, _ := Local.lookup(t.sec + internalToUnix - int64(offset))
+			if name == zoneName && off == offset {
+				t.sec -= int64(offset)
+				t.loc = Local
+				return t, nil
+			}
+		}
+
+		// Otherwise, create fake zone with unknown offset.
+		t.loc = FixedZone(zoneName, 0)
+		return t, nil
+	}
+
+	// Otherwise, fall back to UTC.
+	return t, nil
 }
 
-func (t *Time) parseNanoseconds(value string, nbytes int) (rangErrString string, err error) {
+func parseNanoseconds(value string, nbytes int) (ns int, rangeErrString string, err error) {
 	if value[0] != '.' {
-		return "", errBad
+		err = errBad
+		return
 	}
-	var ns int
-	ns, err = strconv.Atoi(value[1:nbytes])
+	ns, err = atoi(value[1:nbytes])
 	if err != nil {
-		return "", err
+		return
 	}
 	if ns < 0 || 1e9 <= ns {
-		return "fractional second", nil
+		rangeErrString = "fractional second"
+		return
 	}
 	// We need nanoseconds, which means scaling by the number
 	// of missing digits in the format, maximum length 10. If it's
@@ -749,6 +891,5 @@ func (t *Time) parseNanoseconds(value string, nbytes int) (rangErrString string,
 	for i := 0; i < scaleDigits; i++ {
 		ns *= 10
 	}
-	t.Nanosecond = ns
 	return
 }
diff --git a/libgo/go/time/internal_test.go b/libgo/go/time/internal_test.go
index d7e7076539f..2c4df335f9b 100644
--- a/libgo/go/time/internal_test.go
+++ b/libgo/go/time/internal_test.go
@@ -6,7 +6,7 @@ package time
 
 func init() {
 	// force US/Pacific for time zone tests
-	onceSetupZone.Do(setupTestingZone)
+	localOnce.Do(initTestingZone)
 }
 
 var Interrupt = interrupt
diff --git a/libgo/go/time/sleep.go b/libgo/go/time/sleep.go
index 967fca09b99..1e23118f378 100644
--- a/libgo/go/time/sleep.go
+++ b/libgo/go/time/sleep.go
@@ -4,6 +4,11 @@
 
 package time
 
+func nano() int64 {
+	sec, nsec := now()
+	return sec*1e9 + int64(nsec)
+}
+
 // Interface to timers implemented in package runtime.
 // Must be in sync with ../runtime/runtime.h:/^struct.Timer$
 type runtimeTimer struct {
@@ -21,7 +26,7 @@ func stopTimer(*runtimeTimer) bool
 // When the Timer expires, the current time will be sent on C,
 // unless the Timer was created by AfterFunc.
 type Timer struct {
-	C <-chan int64
+	C <-chan Time
 	r runtimeTimer
 }
 
@@ -34,12 +39,12 @@ func (t *Timer) Stop() (ok bool) {
 
 // NewTimer creates a new Timer that will send
 // the current time on its channel after at least ns nanoseconds.
-func NewTimer(ns int64) *Timer {
-	c := make(chan int64, 1)
+func NewTimer(d Duration) *Timer {
+	c := make(chan Time, 1)
 	t := &Timer{
 		C: c,
 		r: runtimeTimer{
-			when: Nanoseconds() + ns,
+			when: nano() + int64(d),
 			f:    sendTime,
 			arg:  c,
 		},
@@ -55,16 +60,16 @@ func sendTime(now int64, c interface{}) {
 	// the desired behavior when the reader gets behind,
 	// because the sends are periodic.
 	select {
-	case c.(chan int64) <- now:
+	case c.(chan Time) <- Unix(0, now):
 	default:
 	}
 }
 
-// After waits at least ns nanoseconds before sending the current time
+// After waits for the duration to elapse and then sends the current time
 // on the returned channel.
 // It is equivalent to NewTimer(ns).C.
-func After(ns int64) <-chan int64 {
-	return NewTimer(ns).C
+func After(d Duration) <-chan Time {
+	return NewTimer(d).C
 }
 
 // AfterFunc waits at least ns nanoseconds before calling f
@@ -73,7 +78,7 @@ func After(ns int64) <-chan int64 {
 func AfterFunc(ns int64, f func()) *Timer {
 	t := &Timer{
 		r: runtimeTimer{
-			when: Nanoseconds() + ns,
+			when: nano() + ns,
 			f:    goFunc,
 			arg:  f,
 		},
diff --git a/libgo/go/time/sleep_test.go b/libgo/go/time/sleep_test.go
index 9171da3af1c..cbcc897fd40 100644
--- a/libgo/go/time/sleep_test.go
+++ b/libgo/go/time/sleep_test.go
@@ -15,16 +15,16 @@ import (
 )
 
 func TestSleep(t *testing.T) {
-	const delay = int64(100e6)
+	const delay = 100 * Millisecond
 	go func() {
 		Sleep(delay / 2)
 		Interrupt()
 	}()
-	start := Nanoseconds()
+	start := Now()
 	Sleep(delay)
-	duration := Nanoseconds() - start
+	duration := Now().Sub(start)
 	if duration < delay {
-		t.Fatalf("Sleep(%d) slept for only %d ns", delay, duration)
+		t.Fatalf("Sleep(%s) slept for only %s", delay, duration)
 	}
 }
 
@@ -96,32 +96,32 @@ func BenchmarkStop(b *testing.B) {
 }
 
 func TestAfter(t *testing.T) {
-	const delay = int64(100e6)
-	start := Nanoseconds()
+	const delay = 100 * Millisecond
+	start := Now()
 	end := <-After(delay)
-	if duration := Nanoseconds() - start; duration < delay {
-		t.Fatalf("After(%d) slept for only %d ns", delay, duration)
+	if duration := Now().Sub(start); duration < delay {
+		t.Fatalf("After(%s) slept for only %d ns", delay, duration)
 	}
-	if min := start + delay; end < min {
-		t.Fatalf("After(%d) expect >= %d, got %d", delay, min, end)
+	if min := start.Add(delay); end.Before(min) {
+		t.Fatalf("After(%s) expect >= %s, got %s", delay, min, end)
 	}
 }
 
 func TestAfterTick(t *testing.T) {
 	const (
-		Delta = 100 * 1e6
+		Delta = 100 * Millisecond
 		Count = 10
 	)
-	t0 := Nanoseconds()
+	t0 := Now()
 	for i := 0; i < Count; i++ {
 		<-After(Delta)
 	}
-	t1 := Nanoseconds()
-	ns := t1 - t0
-	target := int64(Delta * Count)
+	t1 := Now()
+	d := t1.Sub(t0)
+	target := Delta * Count
 	slop := target * 2 / 10
-	if ns < target-slop || ns > target+slop {
-		t.Fatalf("%d ticks of %g ns took %g ns, expected %g", Count, float64(Delta), float64(ns), float64(target))
+	if d < target-slop || d > target+slop {
+		t.Fatalf("%d ticks of %s took %s, expected %s", Count, Delta, d, target)
 	}
 }
 
@@ -171,38 +171,54 @@ var slots = []int{5, 3, 6, 6, 6, 1, 1, 2, 7, 9, 4, 8 /*0*/ }
 
 type afterResult struct {
 	slot int
-	t    int64
+	t    Time
 }
 
-func await(slot int, result chan<- afterResult, ac <-chan int64) {
+func await(slot int, result chan<- afterResult, ac <-chan Time) {
 	result <- afterResult{slot, <-ac}
 }
 
 func testAfterQueuing(t *testing.T) error {
 	const (
-		Delta = 100 * 1e6
+		Delta = 100 * Millisecond
 	)
 	// make the result channel buffered because we don't want
 	// to depend on channel queueing semantics that might
 	// possibly change in the future.
 	result := make(chan afterResult, len(slots))
 
-	t0 := Nanoseconds()
+	t0 := Now()
 	for _, slot := range slots {
-		go await(slot, result, After(int64(slot)*Delta))
+		go await(slot, result, After(Duration(slot)*Delta))
 	}
 	sort.Ints(slots)
 	for _, slot := range slots {
 		r := <-result
 		if r.slot != slot {
-			return fmt.Errorf("after queue got slot %d, expected %d", r.slot, slot)
+			return fmt.Errorf("after slot %d, expected %d", r.slot, slot)
 		}
-		ns := r.t - t0
-		target := int64(slot * Delta)
-		slop := int64(Delta) / 4
-		if ns < target-slop || ns > target+slop {
-			return fmt.Errorf("after queue slot %d arrived at %g, expected [%g,%g]", slot, float64(ns), float64(target-slop), float64(target+slop))
+		dt := r.t.Sub(t0)
+		target := Duration(slot) * Delta
+		slop := Delta / 4
+		if dt < target-slop || dt > target+slop {
+			return fmt.Errorf("After(%s) arrived at %s, expected [%s,%s]", target, dt, target-slop, target+slop)
 		}
 	}
 	return nil
 }
+
+func TestTimerStopStress(t *testing.T) {
+	if testing.Short() {
+		return
+	}
+	for i := 0; i < 100; i++ {
+		go func(i int) {
+			timer := AfterFunc(2e9, func() {
+				t.Fatalf("timer %d was not stopped", i)
+			})
+			Sleep(1e9)
+			timer.Stop()
+		}(i)
+	}
+	Sleep(3e9)
+}
diff --git a/libgo/go/time/sys.go b/libgo/go/time/sys.go
index a5e529b814a..fe6bc27d301 100644
--- a/libgo/go/time/sys.go
+++ b/libgo/go/time/sys.go
@@ -4,17 +4,33 @@
 
 package time
 
-// Seconds reports the number of seconds since the Unix epoch,
-// January 1, 1970 00:00:00 UTC.
-func Seconds() int64 {
-	return Nanoseconds() / 1e9
+import "syscall"
+
+// Sleep pauses the current goroutine for the duration d.
+func Sleep(d Duration)
+
+// readFile reads and returns the content of the named file.
+// It is a trivial implementation of ioutil.ReadFile, reimplemented
+// here to avoid depending on io/ioutil or os.
+func readFile(name string) ([]byte, error) {
+	f, err := syscall.Open(name, syscall.O_RDONLY, 0)
+	if err != nil {
+		return nil, err
+	}
+	defer syscall.Close(f)
+	var (
+		buf [4096]byte
+		ret []byte
+		n   int
+	)
+	for {
+		n, err = syscall.Read(f, buf[:])
+		if n > 0 {
+			ret = append(ret, buf[:n]...)
+		}
+		if n == 0 || err != nil {
+			break
+		}
+	}
+	return ret, err
 }
-
-// Nanoseconds is implemented by package runtime.
-
-// Nanoseconds reports the number of nanoseconds since the Unix epoch,
-// January 1, 1970 00:00:00 UTC.
-func Nanoseconds() int64
-
-// Sleep pauses the current goroutine for at least ns nanoseconds.
-func Sleep(ns int64)
diff --git a/libgo/go/time/sys_unix.go b/libgo/go/time/sys_unix.go
index 3d313228b01..715d186be17 100644
--- a/libgo/go/time/sys_unix.go
+++ b/libgo/go/time/sys_unix.go
@@ -6,12 +6,9 @@
 
 package time
 
-import (
-	"os"
-	"syscall"
-)
+import "syscall"
 
 // for testing: whatever interrupts a sleep
 func interrupt() {
-	syscall.Kill(os.Getpid(), syscall.SIGCHLD)
+	syscall.Kill(syscall.Getpid(), syscall.SIGCHLD)
 }
diff --git a/libgo/go/time/tick.go b/libgo/go/time/tick.go
index 95941a1e819..4440c2207b3 100644
--- a/libgo/go/time/tick.go
+++ b/libgo/go/time/tick.go
@@ -9,27 +9,27 @@ import "errors"
 // A Ticker holds a synchronous channel that delivers `ticks' of a clock
 // at intervals.
 type Ticker struct {
-	C <-chan int64 // The channel on which the ticks are delivered.
+	C <-chan Time // The channel on which the ticks are delivered.
 	r runtimeTimer
 }
 
-// NewTicker returns a new Ticker containing a channel that will
-// send the time, in nanoseconds, every ns nanoseconds.  It adjusts the
-// intervals to make up for pauses in delivery of the ticks. The value of
-// ns must be greater than zero; if not, NewTicker will panic.
-func NewTicker(ns int64) *Ticker {
-	if ns <= 0 {
+// NewTicker returns a new Ticker containing a channel that will send the
+// time, in nanoseconds, with a period specified by the duration argument.
+// It adjusts the intervals or drops ticks to make up for slow receivers.
+// The duration d must be greater than zero; if not, NewTicker will panic.
+func NewTicker(d Duration) *Ticker {
+	if d <= 0 {
 		panic(errors.New("non-positive interval for NewTicker"))
 	}
 	// Give the channel a 1-element time buffer.
 	// If the client falls behind while reading, we drop ticks
 	// on the floor until the client catches up.
-	c := make(chan int64, 1)
+	c := make(chan Time, 1)
 	t := &Ticker{
 		C: c,
 		r: runtimeTimer{
-			when:   Nanoseconds() + ns,
-			period: ns,
+			when:   nano() + int64(d),
+			period: int64(d),
 			f:      sendTime,
 			arg:    c,
 		},
@@ -45,9 +45,9 @@ func (t *Ticker) Stop() {
 
 // Tick is a convenience wrapper for NewTicker providing access to the ticking
 // channel only.  Useful for clients that have no need to shut down the ticker.
-func Tick(ns int64) <-chan int64 {
-	if ns <= 0 {
+func Tick(d Duration) <-chan Time {
+	if d <= 0 {
 		return nil
 	}
-	return NewTicker(ns).C
+	return NewTicker(d).C
 }
diff --git a/libgo/go/time/tick_test.go b/libgo/go/time/tick_test.go
index 4dcb63956b2..36349349ce0 100644
--- a/libgo/go/time/tick_test.go
+++ b/libgo/go/time/tick_test.go
@@ -11,21 +11,21 @@ import (
 
 func TestTicker(t *testing.T) {
 	const (
-		Delta = 100 * 1e6
+		Delta = 100 * Millisecond
 		Count = 10
 	)
 	ticker := NewTicker(Delta)
-	t0 := Nanoseconds()
+	t0 := Now()
 	for i := 0; i < Count; i++ {
 		<-ticker.C
 	}
 	ticker.Stop()
-	t1 := Nanoseconds()
-	ns := t1 - t0
-	target := int64(Delta * Count)
+	t1 := Now()
+	dt := t1.Sub(t0)
+	target := Delta * Count
 	slop := target * 2 / 10
-	if ns < target-slop || ns > target+slop {
-		t.Fatalf("%d ticks of %g ns took %g ns, expected %g", Count, float64(Delta), float64(ns), float64(target))
+	if dt < target-slop || dt > target+slop {
+		t.Fatalf("%d %s ticks took %s, expected [%s,%s]", Count, Delta, dt, target-slop, target+slop)
 	}
 	// Now test that the ticker stopped
 	Sleep(2 * Delta)
diff --git a/libgo/go/time/time.go b/libgo/go/time/time.go
index e11d17731b4..04ed86cf25f 100644
--- a/libgo/go/time/time.go
+++ b/libgo/go/time/time.go
@@ -3,11 +3,109 @@
 // license that can be found in the LICENSE file.
 
 // Package time provides functionality for measuring and displaying time.
+//
+// The calendrical calculations always assume a Gregorian calendar.
 package time
 
-// Days of the week.
+// A Time represents an instant in time with nanosecond precision.
+//
+// Programs using times should typically store and pass them as values,
+// not pointers.  That is, time variables and struct fields should be of
+// type time.Time, not *time.Time.
+//
+// Time instants can be compared using the Before, After, and Equal methods.
+// The Sub method subtracts two instants, producing a Duration.
+// The Add method adds a Time and a Duration, producing a Time.
+//
+// The zero value of type Time is January 1, year 1, 00:00:00.000000000 UTC.
+// As this time is unlikely to come up in practice, the IsZero method gives
+// a simple way of detecting a time that has not been initialized explicitly.
+//
+// Each Time has associated with it a Location, consulted when computing the
+// presentation form of the time, such as in the Format, Hour, and Year methods.
+// The methods Local, UTC, and In return a Time with a specific location.
+// Changing the location in this way changes only the presentation; it does not
+// change the instant in time being denoted and therefore does not affect the
+// computations described in earlier paragraphs.
+//
+type Time struct {
+	// sec gives the number of seconds elapsed since
+	// January 1, year 1 00:00:00 UTC.
+	sec int64
+
+	// nsec specifies a non-negative nanosecond
+	// offset within the second named by Seconds.
+	// It must be in the range [0, 999999999].
+	nsec int32
+
+	// loc specifies the Location that should be used to
+	// determine the minute, hour, month, day, and year
+	// that correspond to this Time.
+	// Only the zero Time has a nil Location.
+	// In that case it is interpreted to mean UTC.
+	loc *Location
+}
+
+// After reports whether the time instant t is after u.
+func (t Time) After(u Time) bool {
+	return t.sec > u.sec || t.sec == u.sec && t.nsec > u.nsec
+}
+
+// Before reports whether the time instant t is before u.
+func (t Time) Before(u Time) bool {
+	return t.sec < u.sec || t.sec == u.sec && t.nsec < u.nsec
+}
+
+// Equal reports whether t and u represent the same time instant.
+// Two times can be equal even if they are in different locations.
+// For example, 6:00 +0200 CEST and 4:00 UTC are Equal.
+// This comparison is different from using t == u, which also compares
+// the locations.
+func (t Time) Equal(u Time) bool {
+	return t.sec == u.sec && t.nsec == u.nsec
+}
+
+// A Month specifies a month of the year (January = 1, ...).
+type Month int
+
 const (
-	Sunday = iota
+	January Month = 1 + iota
+	February
+	March
+	April
+	May
+	June
+	July
+	August
+	September
+	October
+	November
+	December
+)
+
+var months = [...]string{
+	"January",
+	"February",
+	"March",
+	"April",
+	"May",
+	"June",
+	"July",
+	"August",
+	"September",
+	"October",
+	"November",
+	"December",
+}
+
+// String returns the English name of the month ("January", "February", ...).
+func (m Month) String() string { return months[m-1] }
+
+// A Weekday specifies a day of the week (Sunday = 0, ...).
+type Weekday int
+
+const (
+	Sunday Weekday = iota
 	Monday
 	Tuesday
 	Wednesday
@@ -16,284 +114,749 @@ const (
 	Saturday
 )
 
-// Time is the struct representing a parsed time value.
-type Time struct {
-	Year                 int64  // 2006 is 2006
-	Month, Day           int    // Jan-2 is 1, 2
-	Hour, Minute, Second int    // 15:04:05 is 15, 4, 5.
-	Nanosecond           int    // Fractional second.
-	ZoneOffset           int    // seconds east of UTC, e.g. -7*60*60 for -0700
-	Zone                 string // e.g., "MST"
+var days = [...]string{
+	"Sunday",
+	"Monday",
+	"Tuesday",
+	"Wednesday",
+	"Thursday",
+	"Friday",
+	"Saturday",
 }
 
-var nonleapyear = []int{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
-var leapyear = []int{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
+// String returns the English name of the day ("Sunday", "Monday", ...).
+func (d Weekday) String() string { return days[d] }
 
-func months(year int64) []int {
-	if year%4 == 0 && (year%100 != 0 || year%400 == 0) {
-		return leapyear
-	}
-	return nonleapyear
-}
+// 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
+// (1-1-1 00:00:00 UTC), (2) is unlikely enough to arise in practice to
+// 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
+// for negative values, so that the remainder is always positive, but
+// Go's division (like most hardware divison instructions) rounds to
+// zero.  We can still do those computations and then adjust the result
+// for a negative numerator, but it's annoying to write the adjustment
+// over and over.  Instead, we can change to a different epoch so long
+// ago that all the times we care about will be positive, and then round
+// to zero and round down coincide.  These presentation routines already
+// have to add the zone offset, so adding the translation to the
+// alternate epoch is cheap.  For example, having a non-negative time t
+// means that we can write
+//
+//	sec = t % 60
+//
+// instead of
+//
+//	sec = t % 60
+//	if sec < 0 {
+//		sec += 60
+//	}
+//
+// 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
+// cycle boundaries so that the exceptional years are always delayed as
+// long as possible.  That means choosing a year equal to 1 mod 400, so
+// that the first leap year is the 4th year, the first missed leap year
+// 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
+// west of UTC, since it is year 0.  It doesn't seem tenable to say that
+// 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.
 
 const (
-	secondsPerDay   = 24 * 60 * 60
-	daysPer400Years = 365*400 + 97
-	daysPer100Years = 365*100 + 24
-	daysPer4Years   = 365*4 + 1
-	days1970To2001  = 31*365 + 8
+	// The unsigned zero year for internal calculations.
+	// Must be 1 mod 400, and times before it will not compute correctly,
+	// but otherwise can be changed at will.
+	absoluteZeroYear = -292277022399
+
+	// The year of the zero Time.
+	// Assumed by the unixToInternal computation below.
+	internalYear = 1
+
+	// The year of the zero Unix time.
+	unixYear = 1970
+
+	// Offsets to convert between internal and absolute or Unix times.
+	absoluteToInternal int64 = (absoluteZeroYear - internalYear) * 365.2425 * secondsPerDay
+	internalToAbsolute       = -absoluteToInternal
+
+	unixToInternal int64 = (1969*365 + 1969/4 - 1969/100 + 1969/400) * secondsPerDay
+	internalToUnix int64 = -unixToInternal
 )
 
-// SecondsToUTC converts sec, in number of seconds since the Unix epoch,
-// into a parsed Time value in the UTC time zone.
-func SecondsToUTC(sec int64) *Time {
-	t := new(Time)
-
-	// Split into time and day.
-	day := sec / secondsPerDay
-	sec -= day * secondsPerDay
-	if sec < 0 {
-		day--
-		sec += secondsPerDay
-	}
-
-	// Time
-	t.Hour = int(sec / 3600)
-	t.Minute = int((sec / 60) % 60)
-	t.Second = int(sec % 60)
-
-	// Change day from 0 = 1970 to 0 = 2001,
-	// to make leap year calculations easier
-	// (2001 begins 4-, 100-, and 400-year cycles ending in a leap year.)
-	day -= days1970To2001
-
-	year := int64(2001)
-	if day < 0 {
-		// Go back enough 400 year cycles to make day positive.
-		n := -day/daysPer400Years + 1
-		year -= 400 * n
-		day += daysPer400Years * n
-	}
-
-	// Cut off 400 year cycles.
-	n := day / daysPer400Years
-	year += 400 * n
-	day -= daysPer400Years * n
-
-	// Cut off 100-year cycles
-	n = day / daysPer100Years
-	if n > 3 { // happens on last day of 400th year
-		n = 3
-	}
-	year += 100 * n
-	day -= daysPer100Years * n
-
-	// Cut off 4-year cycles
-	n = day / daysPer4Years
-	if n > 24 { // happens on last day of 100th year
-		n = 24
-	}
-	year += 4 * n
-	day -= daysPer4Years * n
-
-	// Cut off non-leap years.
-	n = day / 365
-	if n > 3 { // happens on last day of 4th year
-		n = 3
-	}
-	year += n
-	day -= 365 * n
-
-	t.Year = year
-
-	// If someone ever needs yearday,
-	// tyearday = day (+1?)
-
-	months := months(year)
-	var m int
-	yday := int(day)
-	for m = 0; m < 12 && yday >= months[m]; m++ {
-		yday -= months[m]
-	}
-	t.Month = m + 1
-	t.Day = yday + 1
-	t.Zone = "UTC"
-
-	return t
+// IsZero reports whether t represents the zero time instant,
+// January 1, year 1, 00:00:00 UTC.
+func (t Time) IsZero() bool {
+	return t.sec == 0 && t.nsec == 0
 }
 
-// NanosecondsToUTC converts nsec, in number of nanoseconds since the Unix epoch,
-// into a parsed Time value in the UTC time zone.
-func NanosecondsToUTC(nsec int64) *Time {
-	// This one calls SecondsToUTC rather than the other way around because
-	// that admits a much larger span of time; NanosecondsToUTC is limited
-	// to a few hundred years only.
-	t := SecondsToUTC(nsec / 1e9)
-	t.Nanosecond = int(nsec % 1e9)
-	return t
-}
-
-// UTC returns the current time as a parsed Time value in the UTC time zone.
-func UTC() *Time { return NanosecondsToUTC(Nanoseconds()) }
-
-// SecondsToLocalTime converts sec, in number of seconds since the Unix epoch,
-// into a parsed Time value in the local time zone.
-func SecondsToLocalTime(sec int64) *Time {
-	z, offset := lookupTimezone(sec)
-	t := SecondsToUTC(sec + int64(offset))
-	t.Zone = z
-	t.ZoneOffset = offset
-	return t
-}
-
-// NanosecondsToLocalTime converts nsec, in number of nanoseconds since the Unix epoch,
-// into a parsed Time value in the local time zone.
-func NanosecondsToLocalTime(nsec int64) *Time {
-	t := SecondsToLocalTime(nsec / 1e9)
-	t.Nanosecond = int(nsec % 1e9)
-	return t
-}
-
-// LocalTime returns the current time as a parsed Time value in the local time zone.
-func LocalTime() *Time { return NanosecondsToLocalTime(Nanoseconds()) }
-
-// Seconds returns the number of seconds since January 1, 1970 represented by the
-// parsed Time value.
-func (t *Time) Seconds() int64 {
-	// First, accumulate days since January 1, 2001.
-	// Using 2001 instead of 1970 makes the leap-year
-	// handling easier (see SecondsToUTC), because
-	// it is at the beginning of the 4-, 100-, and 400-year cycles.
-	day := int64(0)
-
-	// Rewrite year to be >= 2001.
-	year := t.Year
-	if year < 2001 {
-		n := (2001-year)/400 + 1
-		year += 400 * n
-		day -= daysPer400Years * n
+// abs returns the time t as an absolute time, adjusted by the zone offset.
+// It is called when computing a presentation property like Month or Hour.
+func (t Time) abs() uint64 {
+	l := t.loc
+	if l == nil {
+		l = &utcLoc
 	}
-
-	// Add in days from 400-year cycles.
-	n := (year - 2001) / 400
-	year -= 400 * n
-	day += daysPer400Years * n
-
-	// Add in 100-year cycles.
-	n = (year - 2001) / 100
-	year -= 100 * n
-	day += daysPer100Years * n
-
-	// Add in 4-year cycles.
-	n = (year - 2001) / 4
-	year -= 4 * n
-	day += daysPer4Years * n
-
-	// Add in non-leap years.
-	n = year - 2001
-	day += 365 * n
-
-	// Add in days this year.
-	months := months(t.Year)
-	for m := 0; m < t.Month-1; m++ {
-		day += int64(months[m])
+	// Avoid function call if we hit the local time cache.
+	sec := t.sec + internalToUnix
+	if l != &utcLoc {
+		if l.cacheZone != nil && l.cacheStart <= sec && sec < l.cacheEnd {
+			sec += int64(l.cacheZone.offset)
+		} else {
+			_, offset, _, _, _ := l.lookup(sec)
+			sec += int64(offset)
+		}
 	}
-	day += int64(t.Day - 1)
-
-	// Convert days to seconds since January 1, 2001.
-	sec := day * secondsPerDay
-
-	// Add in time elapsed today.
-	sec += int64(t.Hour) * 3600
-	sec += int64(t.Minute) * 60
-	sec += int64(t.Second)
-
-	// Convert from seconds since 2001 to seconds since 1970.
-	sec += days1970To2001 * secondsPerDay
-
-	// Account for local time zone.
-	sec -= int64(t.ZoneOffset)
-	return sec
+	return uint64(sec + (unixToInternal + internalToAbsolute))
 }
 
-// Nanoseconds returns the number of nanoseconds since January 1, 1970 represented by the
-// parsed Time value.
-func (t *Time) Nanoseconds() int64 {
-	return t.Seconds()*1e9 + int64(t.Nanosecond)
-}
-
-// Weekday returns the time's day of the week. Sunday is day 0.
-func (t *Time) Weekday() int {
-	sec := t.Seconds() + int64(t.ZoneOffset)
-	day := sec / secondsPerDay
-	sec -= day * secondsPerDay
-	if sec < 0 {
-		day--
-	}
-	// Day 0 = January 1, 1970 was a Thursday
-	weekday := int((day + Thursday) % 7)
-	if weekday < 0 {
-		weekday += 7
-	}
-	return weekday
-}
-
-// julianDayNumber returns the time's Julian Day Number
-// relative to the epoch 12:00 January 1, 4713 BC, Monday.
-func julianDayNumber(year int64, month, day int) int64 {
-	a := int64(14-month) / 12
-	y := year + 4800 - a
-	m := int64(month) + 12*a - 3
-	return int64(day) + (153*m+2)/5 + 365*y + y/4 - y/100 + y/400 - 32045
-}
-
-// startOfFirstWeek returns the julian day number of the first day
-// of the first week of the given year.
-func startOfFirstWeek(year int64) (d int64) {
-	jan01 := julianDayNumber(year, 1, 1)
-	weekday := (jan01 % 7) + 1
-	if weekday <= 4 {
-		d = jan01 - weekday + 1
-	} else {
-		d = jan01 + 8 - weekday
-	}
+// Date returns the year, month, and day in which t occurs.
+func (t Time) Date() (year int, month Month, day int) {
+	year, month, day, _ = t.date(true)
 	return
 }
 
-// dayOfWeek returns the weekday of the given date.
-func dayOfWeek(year int64, month, day int) int {
-	t := Time{Year: year, Month: month, Day: day}
-	return t.Weekday()
+// Year returns the year in which t occurs.
+func (t Time) Year() int {
+	year, _, _, _ := t.date(false)
+	return year
 }
 
-// ISOWeek returns the time's year and week number according to ISO 8601. 
+// Month returns the month of the year specified by t.
+func (t Time) Month() Month {
+	_, month, _, _ := t.date(true)
+	return month
+}
+
+// Day returns the day of the month specified by t.
+func (t Time) Day() int {
+	_, _, day, _ := t.date(true)
+	return day
+}
+
+// Weekday returns the day of the week specified by t.
+func (t Time) Weekday() Weekday {
+	// January 1 of the absolute year, like January 1 of 2001, was a Monday.
+	sec := (t.abs() + uint64(Monday)*secondsPerDay) % secondsPerWeek
+	return Weekday(int(sec) / secondsPerDay)
+}
+
+// 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 
 // of year n+1.
-func (t *Time) ISOWeek() (year int64, week int) {
-	d := julianDayNumber(t.Year, t.Month, t.Day)
-	week1Start := startOfFirstWeek(t.Year)
+func (t Time) ISOWeek() (year, week int) {
+	year, month, day, yday := t.date(true)
+	wday := int(t.Weekday()+6) % 7 // weekday but Monday = 0.
+	const (
+		Mon int = iota
+		Tue
+		Wed
+		Thu
+		Fri
+		Sat
+		Sun
+	)
 
-	if d < week1Start {
-		// Previous year, week 52 or 53
-		year = t.Year - 1
-		if dayOfWeek(t.Year-1, 1, 1) == 4 || dayOfWeek(t.Year-1, 12, 31) == 4 {
-			week = 53
-		} else {
-			week = 52
+	// Calculate week as number of Mondays in year up to
+	// and including today, plus 1 because the first week is week 0.
+	// Putting the + 1 inside the numerator as a + 7 keeps the
+	// numerator from being negative, which would cause it to
+	// round incorrectly.
+	week = (yday - wday + 7) / 7
+
+	// The week number is now correct under the assumption
+	// that the first Monday of the year is in week 1.
+	// If Jan 1 is a Tuesday, Wednesday, or Thursday, the first Monday
+	// is actually in week 2.
+	jan1wday := (wday - yday + 7*53) % 7
+	if Tue <= jan1wday && jan1wday <= Thu {
+		week++
+	}
+
+	// If the week number is still 0, we're in early January but in
+	// the last week of last year.
+	if week == 0 {
+		year--
+		week = 52
+		// A year has 53 weeks when Jan 1 or Dec 31 is a Thursday,
+		// meaning Jan 1 of the next year is a Friday
+		// or it was a leap year and Jan 1 of the next year is a Saturday.
+		if jan1wday == Fri || (jan1wday == Sat && isLeap(year)) {
+			week++
 		}
-		return
 	}
 
-	if d < startOfFirstWeek(t.Year+1) {
-		// Current year, week 01..52(,53)
-		year = t.Year
-		week = int((d-week1Start)/7 + 1)
-		return
+	// December 29 to 31 are in week 1 of next year if
+	// they are after the last Thursday of the year and
+	// December 31 is a Monday, Tuesday, or Wednesday.
+	if month == December && day >= 29 && wday < Thu {
+		if dec31wday := (wday + 31 - day) % 7; Mon <= dec31wday && dec31wday <= Wed {
+			year++
+			week = 1
+		}
 	}
 
-	// Next year, week 1
-	year = t.Year + 1
-	week = 1
 	return
 }
+
+// Clock returns the hour, minute, and second within the day specified by t.
+func (t Time) Clock() (hour, min, sec int) {
+	sec = int(t.abs() % secondsPerDay)
+	hour = sec / secondsPerHour
+	sec -= hour * secondsPerHour
+	min = sec / secondsPerMinute
+	sec -= min * secondsPerMinute
+	return
+}
+
+// Hour returns the hour within the day specified by t, in the range [0, 23].
+func (t Time) Hour() int {
+	return int(t.abs()%secondsPerDay) / secondsPerHour
+}
+
+// Minute returns the minute offset within the hour specified by t, in the range [0, 59].
+func (t Time) Minute() int {
+	return int(t.abs()%secondsPerHour) / secondsPerMinute
+}
+
+// Second returns the second offset within the minute specified by t, in the range [0, 59].
+func (t Time) Second() int {
+	return int(t.abs() % secondsPerMinute)
+}
+
+// Nanosecond returns the nanosecond offset within the second specified by t,
+// in the range [0, 999999999].
+func (t Time) Nanosecond() int {
+	return int(t.nsec)
+}
+
+// A Duration represents the elapsed time between two instants
+// as an int64 nanosecond count.  The representation limits the
+// largest representable duration to approximately 290 years.
+type Duration int64
+
+// Common durations.  There is no definition for units of Day or larger
+// to avoid confusion across daylight savings time zone transitions.
+const (
+	Nanosecond  Duration = 1
+	Microsecond          = 1000 * Nanosecond
+	Millisecond          = 1000 * Microsecond
+	Second               = 1000 * Millisecond
+	Minute               = 60 * Second
+	Hour                 = 60 * Minute
+)
+
+// Duration returns a string representing the duration in the form "72h3m0.5s".
+// Leading zero units are omitted.  As a special case, durations less than one
+// second format use a smaller unit (milli-, micro-, or nanoseconds) to ensure
+// that the leading digit is non-zero.  The zero duration formats as 0,
+// with no unit.
+func (d Duration) String() string {
+	// Largest time is 2540400h10m10.000000000s
+	var buf [32]byte
+	w := len(buf)
+
+	u := uint64(d)
+	neg := d < 0
+	if neg {
+		u = -u
+	}
+
+	if u < uint64(Second) {
+		// Special case: if duration is smaller than a second,
+		// use smaller units, like 1.2ms
+		var (
+			prec int
+			unit byte
+		)
+		switch {
+		case u == 0:
+			return "0"
+		case u < uint64(Microsecond):
+			// print nanoseconds
+			prec = 0
+			unit = 'n'
+		case u < uint64(Millisecond):
+			// print microseconds
+			prec = 3
+			unit = 'u'
+		default:
+			// print milliseconds
+			prec = 6
+			unit = 'm'
+		}
+		w -= 2
+		buf[w] = unit
+		buf[w+1] = 's'
+		w, u = fmtFrac(buf[:w], u, prec)
+		w = fmtInt(buf[:w], u)
+	} else {
+		w--
+		buf[w] = 's'
+
+		w, u = fmtFrac(buf[:w], u, 9)
+
+		// u is now integer seconds
+		w = fmtInt(buf[:w], u%60)
+		u /= 60
+
+		// u is now integer minutes
+		if u > 0 {
+			w--
+			buf[w] = 'm'
+			w = fmtInt(buf[:w], u%60)
+			u /= 60
+
+			// u is now integer hours
+			// Stop at hours because days can be different lengths.
+			if u > 0 {
+				w--
+				buf[w] = 'h'
+				w = fmtInt(buf[:w], u)
+			}
+		}
+	}
+
+	if neg {
+		w--
+		buf[w] = '-'
+	}
+
+	return string(buf[w:])
+}
+
+// fmtFrac formats the fraction of v/10**prec (e.g., ".12345") into the
+// tail of buf, omitting trailing zeros.  it omits the decimal
+// point too when the fraction is 0.  It returns the index where the
+// output bytes begin and the value v/10**prec.
+func fmtFrac(buf []byte, v uint64, prec int) (nw int, nv uint64) {
+	// Omit trailing zeros up to and including decimal point.
+	w := len(buf)
+	print := false
+	for i := 0; i < prec; i++ {
+		digit := v % 10
+		print = print || digit != 0
+		if print {
+			w--
+			buf[w] = byte(digit) + '0'
+		}
+		v /= 10
+	}
+	if print {
+		w--
+		buf[w] = '.'
+	}
+	return w, v
+}
+
+// fmtInt formats v into the tail of buf.
+// It returns the index where the output begins.
+func fmtInt(buf []byte, v uint64) int {
+	w := len(buf)
+	if v == 0 {
+		w--
+		buf[w] = '0'
+	} else {
+		for v > 0 {
+			w--
+			buf[w] = byte(v%10) + '0'
+			v /= 10
+		}
+	}
+	return w
+}
+
+// Nanoseconds returns the duration as an integer nanosecond count.
+func (d Duration) Nanoseconds() int64 { return int64(d) }
+
+// These methods return float64 because the dominant
+// use case is for printing a floating point number like 1.5s, and
+// a truncation to integer would make them not useful in those cases.
+// Splitting the integer and fraction ourselves guarantees that
+// converting the returned float64 to an integer rounds the same
+// way that a pure integer conversion would have, even in cases
+// where, say, float64(d.Nanoseconds())/1e9 would have rounded
+// differently.
+
+// Seconds returns the duration as a floating point number of seconds.
+func (d Duration) Seconds() float64 {
+	sec := d / Second
+	nsec := d % Second
+	return float64(sec) + float64(nsec)*1e-9
+}
+
+// Minutes returns the duration as a floating point number of minutes.
+func (d Duration) Minutes() float64 {
+	min := d / Minute
+	nsec := d % Minute
+	return float64(min) + float64(nsec)*(1e-9/60)
+}
+
+// Hours returns the duration as a floating point number of hours.
+func (d Duration) Hours() float64 {
+	hour := d / Hour
+	nsec := d % Hour
+	return float64(hour) + float64(nsec)*(1e-9/60/60)
+}
+
+// Add returns the time t+d.
+func (t Time) Add(d Duration) Time {
+	t.sec += int64(d / 1e9)
+	t.nsec += int32(d % 1e9)
+	if t.nsec > 1e9 {
+		t.sec++
+		t.nsec -= 1e9
+	} else if t.nsec < 0 {
+		t.sec--
+		t.nsec += 1e9
+	}
+	return t
+}
+
+// Sub returns the duration t-u.
+// To compute t-d for a duration d, use t.Add(-d).
+func (t Time) Sub(u Time) Duration {
+	return Duration(t.sec-u.sec)*Second + Duration(t.nsec-u.nsec)
+}
+
+const (
+	secondsPerMinute = 60
+	secondsPerHour   = 60 * 60
+	secondsPerDay    = 24 * secondsPerHour
+	secondsPerWeek   = 7 * secondsPerDay
+	daysPer400Years  = 365*400 + 97
+	daysPer100Years  = 365*100 + 24
+	daysPer4Years    = 365*4 + 1
+	days1970To2001   = 31*365 + 8
+)
+
+// date computes the year and, only when full=true,
+// the month and day in which t occurs.
+func (t Time) date(full bool) (year int, month Month, day int, yday int) {
+	// Split into time and day.
+	d := t.abs() / secondsPerDay
+
+	// Account for 400 year cycles.
+	n := d / daysPer400Years
+	y := 400 * n
+	d -= daysPer400Years * n
+
+	// Cut off 100-year cycles.
+	// The last cycle has one extra leap year, so on the last day
+	// of that year, day / daysPer100Years will be 4 instead of 3.
+	// Cut it back down to 3 by subtracting n>>2.
+	n = d / daysPer100Years
+	n -= n >> 2
+	y += 100 * n
+	d -= daysPer100Years * n
+
+	// Cut off 4-year cycles.
+	// The last cycle has a missing leap year, which does not
+	// affect the computation.
+	n = d / daysPer4Years
+	y += 4 * n
+	d -= daysPer4Years * n
+
+	// Cut off years within a 4-year cycle.
+	// The last year is a leap year, so on the last day of that year,
+	// day / 365 will be 4 instead of 3.  Cut it back down to 3
+	// by subtracting n>>2.
+	n = d / 365
+	n -= n >> 2
+	y += n
+	d -= 365 * n
+
+	year = int(int64(y) + absoluteZeroYear)
+	yday = int(d)
+
+	if !full {
+		return
+	}
+
+	day = yday
+	if isLeap(year) {
+		// Leap year
+		switch {
+		case day > 31+29-1:
+			// After leap day; pretend it wasn't there.
+			day--
+		case day == 31+29-1:
+			// Leap day.
+			month = February
+			day = 29
+			return
+		}
+	}
+
+	// Estimate month on assumption that every month has 31 days.
+	// The estimate may be too low by at most one month, so adjust.
+	month = Month(day / 31)
+	end := int(daysBefore[month+1])
+	var begin int
+	if day >= end {
+		month++
+		begin = end
+	} else {
+		begin = int(daysBefore[month])
+	}
+
+	month++ // because January is 1
+	day = day - begin + 1
+	return
+}
+
+// daysBefore[m] counts the number of days in a non-leap year
+// before month m begins.  There is an entry for m=12, counting
+// the number of days before January of next year (365).
+var daysBefore = [...]int32{
+	0,
+	31,
+	31 + 28,
+	31 + 28 + 31,
+	31 + 28 + 31 + 30,
+	31 + 28 + 31 + 30 + 31,
+	31 + 28 + 31 + 30 + 31 + 30,
+	31 + 28 + 31 + 30 + 31 + 30 + 31,
+	31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
+	31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
+	31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
+	31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
+	31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31,
+}
+
+func daysIn(m Month, year int) int {
+	if m == February && isLeap(year) {
+		return 29
+	}
+	return int(daysBefore[m+1] - daysBefore[m])
+}
+
+// Provided by package runtime.
+func now() (sec int64, nsec int32)
+
+// Now returns the current local time.
+func Now() Time {
+	sec, nsec := now()
+	return Time{sec + unixToInternal, nsec, Local}
+}
+
+// UTC returns t with the location set to UTC.
+func (t Time) UTC() Time {
+	t.loc = UTC
+	return t
+}
+
+// Local returns t with the location set to local time.
+func (t Time) Local() Time {
+	t.loc = Local
+	return t
+}
+
+// In returns t with the location information set to loc.
+//
+// In panics if loc is nil.
+func (t Time) In(loc *Location) Time {
+	if loc == nil {
+		panic("time: missing Location in call to Time.In")
+	}
+	t.loc = loc
+	return t
+}
+
+// Location returns the time zone information associated with t.
+func (t Time) Location() *Location {
+	l := t.loc
+	if l == nil {
+		l = UTC
+	}
+	return l
+}
+
+// Zone computes the time zone in effect at time t, returning the abbreviated
+// name of the zone (such as "CET") and its offset in seconds east of UTC.
+func (t Time) Zone() (name string, offset int) {
+	name, offset, _, _, _ = t.loc.lookup(t.sec + internalToUnix)
+	return
+}
+
+// Unix returns the Unix time, the number of seconds elapsed
+// since January 1, 1970 UTC.
+func (t Time) Unix() int64 {
+	return t.sec + internalToUnix
+}
+
+// UnixNano returns the Unix time, the number of nanoseconds elapsed
+// since January 1, 1970 UTC.
+func (t Time) UnixNano() int64 {
+	return (t.sec+internalToUnix)*1e9 + int64(t.nsec)
+}
+
+// Unix returns the local Time corresponding to the given Unix time,
+// sec seconds and nsec nanoseconds since January 1, 1970 UTC.
+// It is valid to pass nsec outside the range [0, 999999999].
+func Unix(sec int64, nsec int64) Time {
+	if nsec < 0 || nsec >= 1e9 {
+		n := nsec / 1e9
+		sec += n
+		nsec -= n * 1e9
+		if nsec < 0 {
+			nsec += 1e9
+			sec--
+		}
+	}
+	return Time{sec + unixToInternal, int32(nsec), Local}
+}
+
+func isLeap(year int) bool {
+	return year%4 == 0 && (year%100 != 0 || year%400 == 0)
+}
+
+// norm returns nhi, nlo such that
+//	hi * base + lo == nhi * base + nlo
+//	0 <= nlo < base
+func norm(hi, lo, base int) (nhi, nlo int) {
+	if lo < 0 {
+		n := (-lo-1)/base + 1
+		hi -= n
+		lo += n * base
+	}
+	if lo >= base {
+		n := lo / base
+		hi += n
+		lo -= n * base
+	}
+	return hi, lo
+}
+
+// Date returns the Time corresponding to
+//	yyyy-mm-dd hh:mm:ss + nsec nanoseconds
+// in the appropriate zone for that time in the given location.
+//
+// The month, day, hour, min, sec, and nsec values may be outside
+// their usual ranges and will be normalized during the conversion.
+// For example, October 32 converts to November 1.
+//
+// A daylight savings time transition skips or repeats times.
+// For example, in the United States, March 13, 2011 2:15am never occurred,
+// while November 6, 2011 1:15am occurred twice.  In such cases, the
+// choice of time zone, and therefore the time, is not well-defined.
+// Date returns a time that is correct in one of the two zones involved
+// in the transition, but it does not guarantee which.
+//
+// Date panics if loc is nil.
+func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) Time {
+	if loc == nil {
+		panic("time: missing Location in call to Date")
+	}
+
+	// Normalize month, overflowing into year.
+	m := int(month) - 1
+	year, m = norm(year, m, 12)
+	month = Month(m) + 1
+
+	// Normalize nsec, sec, min, hour, overflowing into day.
+	sec, nsec = norm(sec, nsec, 1e9)
+	min, sec = norm(min, sec, 60)
+	hour, min = norm(hour, min, 60)
+	day, hour = norm(day, hour, 24)
+
+	y := uint64(int64(year) - absoluteZeroYear)
+
+	// Compute days since the absolute epoch.
+
+	// Add in days from 400-year cycles.
+	n := y / 400
+	y -= 400 * n
+	d := daysPer400Years * n
+
+	// Add in 100-year cycles.
+	n = y / 100
+	y -= 100 * n
+	d += daysPer100Years * n
+
+	// Add in 4-year cycles.
+	n = y / 4
+	y -= 4 * n
+	d += daysPer4Years * n
+
+	// Add in non-leap years.
+	n = y
+	d += 365 * n
+
+	// Add in days before this month.
+	d += uint64(daysBefore[month-1])
+	if isLeap(year) && month >= March {
+		d++ // February 29
+	}
+
+	// Add in days before today.
+	d += uint64(day - 1)
+
+	// Add in time elapsed today.
+	abs := d * secondsPerDay
+	abs += uint64(hour*secondsPerHour + min*secondsPerMinute + sec)
+
+	unix := int64(abs) + (absoluteToInternal + internalToUnix)
+
+	// Look for zone offset for t, so we can adjust to UTC.
+	// The lookup function expects UTC, so we pass t in the
+	// hope that it will not be too close to a zone transition,
+	// and then adjust if it is.
+	_, offset, _, start, end := loc.lookup(unix)
+	if offset != 0 {
+		switch utc := unix - int64(offset); {
+		case utc < start:
+			_, offset, _, _, _ = loc.lookup(start - 1)
+		case utc >= end:
+			_, offset, _, _, _ = loc.lookup(end)
+		}
+		unix -= int64(offset)
+	}
+
+	return Time{unix + unixToInternal, int32(nsec), loc}
+}
diff --git a/libgo/go/time/time_test.go b/libgo/go/time/time_test.go
index 01b8bea4aad..9590e281a66 100644
--- a/libgo/go/time/time_test.go
+++ b/libgo/go/time/time_test.go
@@ -16,73 +16,89 @@ import (
 // won't be. The purpose of this test is to at least explain why some of
 // the subsequent tests fail.
 func TestZoneData(t *testing.T) {
-	lt := LocalTime()
+	lt := Now()
 	// PST is 8 hours west, PDT is 7 hours west.  We could use the name but it's not unique.
-	if off := lt.ZoneOffset; off != -8*60*60 && off != -7*60*60 {
-		t.Errorf("Unable to find US Pacific time zone data for testing; time zone is %q offset %d", lt.Zone, off)
+	if name, off := lt.Zone(); off != -8*60*60 && off != -7*60*60 {
+		t.Errorf("Unable to find US Pacific time zone data for testing; time zone is %q offset %d", name, off)
 		t.Error("Likely problem: the time zone files have not been installed.")
 	}
 }
 
+// parsedTime is the struct representing a parsed time value.
+type parsedTime struct {
+	Year                 int
+	Month                Month
+	Day                  int
+	Hour, Minute, Second int // 15:04:05 is 15, 4, 5.
+	Nanosecond           int // Fractional second.
+	Weekday              Weekday
+	ZoneOffset           int    // seconds east of UTC, e.g. -7*60*60 for -0700
+	Zone                 string // e.g., "MST"
+}
+
 type TimeTest struct {
 	seconds int64
-	golden  Time
+	golden  parsedTime
 }
 
 var utctests = []TimeTest{
-	{0, Time{1970, 1, 1, 0, 0, 0, 0, 0, "UTC"}},
-	{1221681866, Time{2008, 9, 17, 20, 4, 26, 0, 0, "UTC"}},
-	{-1221681866, Time{1931, 4, 16, 3, 55, 34, 0, 0, "UTC"}},
-	{-11644473600, Time{1601, 1, 1, 0, 0, 0, 0, 0, "UTC"}},
-	{599529660, Time{1988, 12, 31, 0, 1, 0, 0, 0, "UTC"}},
-	{978220860, Time{2000, 12, 31, 0, 1, 0, 0, 0, "UTC"}},
-	{1e18, Time{31688740476, 10, 23, 1, 46, 40, 0, 0, "UTC"}},
-	{-1e18, Time{-31688736537, 3, 10, 22, 13, 20, 0, 0, "UTC"}},
-	{0x7fffffffffffffff, Time{292277026596, 12, 4, 15, 30, 7, 0, 0, "UTC"}},
-	{-0x8000000000000000, Time{-292277022657, 1, 27, 8, 29, 52, 0, 0, "UTC"}},
+	{0, parsedTime{1970, January, 1, 0, 0, 0, 0, Thursday, 0, "UTC"}},
+	{1221681866, parsedTime{2008, September, 17, 20, 4, 26, 0, Wednesday, 0, "UTC"}},
+	{-1221681866, parsedTime{1931, April, 16, 3, 55, 34, 0, Thursday, 0, "UTC"}},
+	{-11644473600, parsedTime{1601, January, 1, 0, 0, 0, 0, Monday, 0, "UTC"}},
+	{599529660, parsedTime{1988, December, 31, 0, 1, 0, 0, Saturday, 0, "UTC"}},
+	{978220860, parsedTime{2000, December, 31, 0, 1, 0, 0, Sunday, 0, "UTC"}},
 }
 
 var nanoutctests = []TimeTest{
-	{0, Time{1970, 1, 1, 0, 0, 0, 1e8, 0, "UTC"}},
-	{1221681866, Time{2008, 9, 17, 20, 4, 26, 2e8, 0, "UTC"}},
+	{0, parsedTime{1970, January, 1, 0, 0, 0, 1e8, Thursday, 0, "UTC"}},
+	{1221681866, parsedTime{2008, September, 17, 20, 4, 26, 2e8, Wednesday, 0, "UTC"}},
 }
 
 var localtests = []TimeTest{
-	{0, Time{1969, 12, 31, 16, 0, 0, 0, -8 * 60 * 60, "PST"}},
-	{1221681866, Time{2008, 9, 17, 13, 4, 26, 0, -7 * 60 * 60, "PDT"}},
+	{0, parsedTime{1969, December, 31, 16, 0, 0, 0, Wednesday, -8 * 60 * 60, "PST"}},
+	{1221681866, parsedTime{2008, September, 17, 13, 4, 26, 0, Wednesday, -7 * 60 * 60, "PDT"}},
 }
 
 var nanolocaltests = []TimeTest{
-	{0, Time{1969, 12, 31, 16, 0, 0, 1e8, -8 * 60 * 60, "PST"}},
-	{1221681866, Time{2008, 9, 17, 13, 4, 26, 3e8, -7 * 60 * 60, "PDT"}},
+	{0, parsedTime{1969, December, 31, 16, 0, 0, 1e8, Wednesday, -8 * 60 * 60, "PST"}},
+	{1221681866, parsedTime{2008, September, 17, 13, 4, 26, 3e8, Wednesday, -7 * 60 * 60, "PDT"}},
 }
 
-func same(t, u *Time) bool {
-	return t.Year == u.Year &&
-		t.Month == u.Month &&
-		t.Day == u.Day &&
-		t.Hour == u.Hour &&
-		t.Minute == u.Minute &&
-		t.Second == u.Second &&
-		t.Nanosecond == u.Nanosecond &&
-		t.Weekday() == u.Weekday() &&
-		t.ZoneOffset == u.ZoneOffset &&
-		t.Zone == u.Zone
+func same(t Time, u *parsedTime) bool {
+	// Check aggregates.
+	year, month, day := t.Date()
+	hour, min, sec := t.Clock()
+	name, offset := t.Zone()
+	if year != u.Year || month != u.Month || day != u.Day ||
+		hour != u.Hour || min != u.Minute || sec != u.Second ||
+		name != u.Zone || offset != u.ZoneOffset {
+		return false
+	}
+	// Check individual entries.
+	return t.Year() == u.Year &&
+		t.Month() == u.Month &&
+		t.Day() == u.Day &&
+		t.Hour() == u.Hour &&
+		t.Minute() == u.Minute &&
+		t.Second() == u.Second &&
+		t.Nanosecond() == u.Nanosecond &&
+		t.Weekday() == u.Weekday
 }
 
 func TestSecondsToUTC(t *testing.T) {
 	for _, test := range utctests {
 		sec := test.seconds
 		golden := &test.golden
-		tm := SecondsToUTC(sec)
-		newsec := tm.Seconds()
+		tm := Unix(sec, 0).UTC()
+		newsec := tm.Unix()
 		if newsec != sec {
 			t.Errorf("SecondsToUTC(%d).Seconds() = %d", sec, newsec)
 		}
 		if !same(tm, golden) {
-			t.Errorf("SecondsToUTC(%d):", sec)
+			t.Errorf("SecondsToUTC(%d):  // %#v", sec, tm)
 			t.Errorf("  want=%+v", *golden)
-			t.Errorf("  have=%+v", *tm)
+			t.Errorf("  have=%v", tm.Format(RFC3339+" MST"))
 		}
 	}
 }
@@ -91,15 +107,15 @@ func TestNanosecondsToUTC(t *testing.T) {
 	for _, test := range nanoutctests {
 		golden := &test.golden
 		nsec := test.seconds*1e9 + int64(golden.Nanosecond)
-		tm := NanosecondsToUTC(nsec)
-		newnsec := tm.Nanoseconds()
+		tm := Unix(0, nsec).UTC()
+		newnsec := tm.Unix()*1e9 + int64(tm.Nanosecond())
 		if newnsec != nsec {
 			t.Errorf("NanosecondsToUTC(%d).Nanoseconds() = %d", nsec, newnsec)
 		}
 		if !same(tm, golden) {
 			t.Errorf("NanosecondsToUTC(%d):", nsec)
 			t.Errorf("  want=%+v", *golden)
-			t.Errorf("  have=%+v", *tm)
+			t.Errorf("  have=%+v", tm.Format(RFC3339+" MST"))
 		}
 	}
 }
@@ -108,38 +124,38 @@ func TestSecondsToLocalTime(t *testing.T) {
 	for _, test := range localtests {
 		sec := test.seconds
 		golden := &test.golden
-		tm := SecondsToLocalTime(sec)
-		newsec := tm.Seconds()
+		tm := Unix(sec, 0)
+		newsec := tm.Unix()
 		if newsec != sec {
 			t.Errorf("SecondsToLocalTime(%d).Seconds() = %d", sec, newsec)
 		}
 		if !same(tm, golden) {
 			t.Errorf("SecondsToLocalTime(%d):", sec)
 			t.Errorf("  want=%+v", *golden)
-			t.Errorf("  have=%+v", *tm)
+			t.Errorf("  have=%+v", tm.Format(RFC3339+" MST"))
 		}
 	}
 }
 
-func TestNanoecondsToLocalTime(t *testing.T) {
+func TestNanosecondsToLocalTime(t *testing.T) {
 	for _, test := range nanolocaltests {
 		golden := &test.golden
 		nsec := test.seconds*1e9 + int64(golden.Nanosecond)
-		tm := NanosecondsToLocalTime(nsec)
-		newnsec := tm.Nanoseconds()
+		tm := Unix(0, nsec)
+		newnsec := tm.Unix()*1e9 + int64(tm.Nanosecond())
 		if newnsec != nsec {
 			t.Errorf("NanosecondsToLocalTime(%d).Seconds() = %d", nsec, newnsec)
 		}
 		if !same(tm, golden) {
 			t.Errorf("NanosecondsToLocalTime(%d):", nsec)
 			t.Errorf("  want=%+v", *golden)
-			t.Errorf("  have=%+v", *tm)
+			t.Errorf("  have=%+v", tm.Format(RFC3339+" MST"))
 		}
 	}
 }
 
 func TestSecondsToUTCAndBack(t *testing.T) {
-	f := func(sec int64) bool { return SecondsToUTC(sec).Seconds() == sec }
+	f := func(sec int64) bool { return Unix(sec, 0).UTC().Unix() == sec }
 	f32 := func(sec int32) bool { return f(int64(sec)) }
 	cfg := &quick.Config{MaxCount: 10000}
 
@@ -153,7 +169,11 @@ func TestSecondsToUTCAndBack(t *testing.T) {
 }
 
 func TestNanosecondsToUTCAndBack(t *testing.T) {
-	f := func(nsec int64) bool { return NanosecondsToUTC(nsec).Nanoseconds() == nsec }
+	f := func(nsec int64) bool {
+		t := Unix(0, nsec).UTC()
+		ns := t.Unix()*1e9 + int64(t.Nanosecond())
+		return ns == nsec
+	}
 	f32 := func(nsec int32) bool { return f(int64(nsec)) }
 	cfg := &quick.Config{MaxCount: 10000}
 
@@ -173,9 +193,9 @@ type TimeFormatTest struct {
 }
 
 var rfc3339Formats = []TimeFormatTest{
-	{Time{2008, 9, 17, 20, 4, 26, 0, 0, "UTC"}, "2008-09-17T20:04:26Z"},
-	{Time{1994, 9, 17, 20, 4, 26, 0, -18000, "EST"}, "1994-09-17T20:04:26-05:00"},
-	{Time{2000, 12, 26, 1, 15, 6, 0, 15600, "OTO"}, "2000-12-26T01:15:06+04:20"},
+	{Date(2008, 9, 17, 20, 4, 26, 0, UTC), "2008-09-17T20:04:26Z"},
+	{Date(1994, 9, 17, 20, 4, 26, 0, FixedZone("EST", -18000)), "1994-09-17T20:04:26-05:00"},
+	{Date(2000, 12, 26, 1, 15, 6, 0, FixedZone("OTO", 15600)), "2000-12-26T01:15:06+04:20"},
 }
 
 func TestRFC3339Conversion(t *testing.T) {
@@ -216,7 +236,7 @@ var formatTests = []FormatTest{
 
 func TestFormat(t *testing.T) {
 	// The numeric time represents Thu Feb  4 21:00:57.012345678 PST 2010
-	time := NanosecondsToLocalTime(1233810057012345678)
+	time := Unix(0, 1233810057012345678)
 	for _, test := range formatTests {
 		result := time.Format(test.format)
 		if result != test.result {
@@ -229,10 +249,10 @@ type ParseTest struct {
 	name       string
 	format     string
 	value      string
-	hasTZ      bool  // contains a time zone
-	hasWD      bool  // contains a weekday
-	yearSign   int64 // sign of year
-	fracDigits int   // number of digits of fractional second
+	hasTZ      bool // contains a time zone
+	hasWD      bool // contains a weekday
+	yearSign   int  // sign of year
+	fracDigits int  // number of digits of fractional second
 }
 
 var parseTests = []ParseTest{
@@ -298,47 +318,48 @@ func TestRubyParse(t *testing.T) {
 	}
 }
 
-func checkTime(time *Time, test *ParseTest, t *testing.T) {
+func checkTime(time Time, test *ParseTest, t *testing.T) {
 	// The time should be Thu Feb  4 21:00:57 PST 2010
-	if test.yearSign*time.Year != 2010 {
-		t.Errorf("%s: bad year: %d not %d", test.name, time.Year, 2010)
+	if test.yearSign*time.Year() != 2010 {
+		t.Errorf("%s: bad year: %d not %d", test.name, time.Year(), 2010)
 	}
-	if time.Month != 2 {
-		t.Errorf("%s: bad month: %d not %d", test.name, time.Month, 2)
+	if time.Month() != February {
+		t.Errorf("%s: bad month: %s not %s", test.name, time.Month(), February)
 	}
-	if time.Day != 4 {
-		t.Errorf("%s: bad day: %d not %d", test.name, time.Day, 4)
+	if time.Day() != 4 {
+		t.Errorf("%s: bad day: %d not %d", test.name, time.Day(), 4)
 	}
-	if time.Hour != 21 {
-		t.Errorf("%s: bad hour: %d not %d", test.name, time.Hour, 21)
+	if time.Hour() != 21 {
+		t.Errorf("%s: bad hour: %d not %d", test.name, time.Hour(), 21)
 	}
-	if time.Minute != 0 {
-		t.Errorf("%s: bad minute: %d not %d", test.name, time.Minute, 0)
+	if time.Minute() != 0 {
+		t.Errorf("%s: bad minute: %d not %d", test.name, time.Minute(), 0)
 	}
-	if time.Second != 57 {
-		t.Errorf("%s: bad second: %d not %d", test.name, time.Second, 57)
+	if time.Second() != 57 {
+		t.Errorf("%s: bad second: %d not %d", test.name, time.Second(), 57)
 	}
 	// Nanoseconds must be checked against the precision of the input.
 	nanosec, err := strconv.Atoui("012345678"[:test.fracDigits] + "000000000"[:9-test.fracDigits])
 	if err != nil {
 		panic(err)
 	}
-	if time.Nanosecond != int(nanosec) {
-		t.Errorf("%s: bad nanosecond: %d not %d", test.name, time.Nanosecond, nanosec)
+	if time.Nanosecond() != int(nanosec) {
+		t.Errorf("%s: bad nanosecond: %d not %d", test.name, time.Nanosecond(), nanosec)
 	}
-	if test.hasTZ && time.ZoneOffset != -28800 {
-		t.Errorf("%s: bad tz offset: %d not %d", test.name, time.ZoneOffset, -28800)
+	name, offset := time.Zone()
+	if test.hasTZ && offset != -28800 {
+		t.Errorf("%s: bad tz offset: %s %d not %d", test.name, name, offset, -28800)
 	}
-	if test.hasWD && time.Weekday() != 4 {
-		t.Errorf("%s: bad weekday: %d not %d", test.name, time.Weekday(), 4)
+	if test.hasWD && time.Weekday() != Thursday {
+		t.Errorf("%s: bad weekday: %s not %s", test.name, time.Weekday(), Thursday)
 	}
 }
 
 func TestFormatAndParse(t *testing.T) {
 	const fmt = "Mon MST " + RFC3339 // all fields
 	f := func(sec int64) bool {
-		t1 := SecondsToLocalTime(sec)
-		if t1.Year < 1000 || t1.Year > 9999 {
+		t1 := Unix(sec, 0)
+		if t1.Year() < 1000 || t1.Year() > 9999 {
 			// not required to work
 			return true
 		}
@@ -347,8 +368,8 @@ func TestFormatAndParse(t *testing.T) {
 			t.Errorf("error: %s", err)
 			return false
 		}
-		if !same(t1, t2) {
-			t.Errorf("different: %q %q", t1, t2)
+		if t1.Unix() != t2.Unix() || t1.Nanosecond() != t2.Nanosecond() {
+			t.Errorf("FormatAndParse %d: %q(%d) %q(%d)", sec, t1, t1.Unix(), t2, t2.Unix())
 			return false
 		}
 		return true
@@ -394,7 +415,7 @@ func TestParseErrors(t *testing.T) {
 }
 
 func TestNoonIs12PM(t *testing.T) {
-	noon := Time{Hour: 12}
+	noon := Date(0, January, 1, 12, 0, 0, 0, UTC)
 	const expect = "12:00PM"
 	got := noon.Format("3:04PM")
 	if got != expect {
@@ -407,7 +428,7 @@ func TestNoonIs12PM(t *testing.T) {
 }
 
 func TestMidnightIs12AM(t *testing.T) {
-	midnight := Time{Hour: 0}
+	midnight := Date(0, January, 1, 0, 0, 0, 0, UTC)
 	expect := "12:00AM"
 	got := midnight.Format("3:04PM")
 	if got != expect {
@@ -424,15 +445,15 @@ func Test12PMIsNoon(t *testing.T) {
 	if err != nil {
 		t.Fatal("error parsing date:", err)
 	}
-	if noon.Hour != 12 {
-		t.Errorf("got %d; expect 12", noon.Hour)
+	if noon.Hour() != 12 {
+		t.Errorf("got %d; expect 12", noon.Hour())
 	}
 	noon, err = Parse("03:04PM", "12:00PM")
 	if err != nil {
 		t.Fatal("error parsing date:", err)
 	}
-	if noon.Hour != 12 {
-		t.Errorf("got %d; expect 12", noon.Hour)
+	if noon.Hour() != 12 {
+		t.Errorf("got %d; expect 12", noon.Hour())
 	}
 }
 
@@ -441,15 +462,15 @@ func Test12AMIsMidnight(t *testing.T) {
 	if err != nil {
 		t.Fatal("error parsing date:", err)
 	}
-	if midnight.Hour != 0 {
-		t.Errorf("got %d; expect 0", midnight.Hour)
+	if midnight.Hour() != 0 {
+		t.Errorf("got %d; expect 0", midnight.Hour())
 	}
 	midnight, err = Parse("03:04PM", "12:00AM")
 	if err != nil {
 		t.Fatal("error parsing date:", err)
 	}
-	if midnight.Hour != 0 {
-		t.Errorf("got %d; expect 0", midnight.Hour)
+	if midnight.Hour() != 0 {
+		t.Errorf("got %d; expect 0", midnight.Hour())
 	}
 }
 
@@ -463,7 +484,7 @@ func TestMissingZone(t *testing.T) {
 	expect := "Thu Feb  2 16:10:03 -0500 2006" // -0500 not EST
 	str := time.Format(UnixDate)               // uses MST as its time zone
 	if str != expect {
-		t.Errorf("expected %q got %q", expect, str)
+		t.Errorf("got %s; expect %s", str, expect)
 	}
 }
 
@@ -473,16 +494,17 @@ func TestMinutesInTimeZone(t *testing.T) {
 		t.Fatal("error parsing date:", err)
 	}
 	expected := (1*60 + 23) * 60
-	if time.ZoneOffset != expected {
-		t.Errorf("ZoneOffset incorrect, expected %d got %d", expected, time.ZoneOffset)
+	_, offset := time.Zone()
+	if offset != expected {
+		t.Errorf("ZoneOffset = %d, want %d", offset, expected)
 	}
 }
 
 type ISOWeekTest struct {
-	year       int64 // year
-	month, day int   // month and day
-	yex        int64 // expected year
-	wex        int   // expected week
+	year       int // year
+	month, day int // month and day
+	yex        int // expected year
+	wex        int // expected week
 }
 
 var isoWeekTests = []ISOWeekTest{
@@ -524,7 +546,7 @@ var isoWeekTests = []ISOWeekTest{
 func TestISOWeek(t *testing.T) {
 	// Selected dates and corner cases
 	for _, wt := range isoWeekTests {
-		dt := &Time{Year: wt.year, Month: wt.month, Day: wt.day}
+		dt := Date(wt.year, Month(wt.month), wt.day, 0, 0, 0, 0, UTC)
 		y, w := dt.ISOWeek()
 		if w != wt.wex || y != wt.yex {
 			t.Errorf("got %d/%d; expected %d/%d for %d-%02d-%02d",
@@ -533,27 +555,91 @@ func TestISOWeek(t *testing.T) {
 	}
 
 	// The only real invariant: Jan 04 is in week 1
-	for year := int64(1950); year < 2100; year++ {
-		if y, w := (&Time{Year: year, Month: 1, Day: 4}).ISOWeek(); y != year || w != 1 {
+	for year := 1950; year < 2100; year++ {
+		if y, w := Date(year, January, 4, 0, 0, 0, 0, UTC).ISOWeek(); y != year || w != 1 {
 			t.Errorf("got %d/%d; expected %d/1 for Jan 04", y, w, year)
 		}
 	}
 }
 
-func BenchmarkSeconds(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		Seconds()
+var durationTests = []struct {
+	str string
+	d   Duration
+}{
+	{"0", 0},
+	{"1ns", 1 * Nanosecond},
+	{"1.1us", 1100 * Nanosecond},
+	{"2.2ms", 2200 * Microsecond},
+	{"3.3s", 3300 * Millisecond},
+	{"4m5s", 4*Minute + 5*Second},
+	{"4m5.001s", 4*Minute + 5001*Millisecond},
+	{"5h6m7.001s", 5*Hour + 6*Minute + 7001*Millisecond},
+	{"8m0.000000001s", 8*Minute + 1*Nanosecond},
+	{"2562047h47m16.854775807s", 1<<63 - 1},
+	{"-2562047h47m16.854775808s", -1 << 63},
+}
+
+func TestDurationString(t *testing.T) {
+	for _, tt := range durationTests {
+		if str := tt.d.String(); str != tt.str {
+			t.Errorf("Duration(%d).String() = %s, want %s", int64(tt.d), str, tt.str)
+		}
+		if tt.d > 0 {
+			if str := (-tt.d).String(); str != "-"+tt.str {
+				t.Errorf("Duration(%d).String() = %s, want %s", int64(-tt.d), str, "-"+tt.str)
+			}
+		}
 	}
 }
 
-func BenchmarkNanoseconds(b *testing.B) {
+var dateTests = []struct {
+	year, month, day, hour, min, sec, nsec int
+	z                                      *Location
+	unix                                   int64
+}{
+	{2011, 11, 6, 1, 0, 0, 0, Local, 1320566400},   // 1:00:00 PDT
+	{2011, 11, 6, 1, 59, 59, 0, Local, 1320569999}, // 1:59:59 PDT
+	{2011, 11, 6, 2, 0, 0, 0, Local, 1320573600},   // 2:00:00 PST
+
+	{2011, 3, 13, 1, 0, 0, 0, Local, 1300006800},   // 1:00:00 PST
+	{2011, 3, 13, 1, 59, 59, 0, Local, 1300010399}, // 1:59:59 PST
+	{2011, 3, 13, 3, 0, 0, 0, Local, 1300010400},   // 3:00:00 PDT
+	{2011, 3, 13, 2, 30, 0, 0, Local, 1300008600},  // 2:30:00 PDT ≡ 1:30 PST
+
+	// Many names for Fri Nov 18 7:56:35 PST 2011
+	{2011, 11, 18, 7, 56, 35, 0, Local, 1321631795},                 // Nov 18 7:56:35
+	{2011, 11, 19, -17, 56, 35, 0, Local, 1321631795},               // Nov 19 -17:56:35
+	{2011, 11, 17, 31, 56, 35, 0, Local, 1321631795},                // Nov 17 31:56:35
+	{2011, 11, 18, 6, 116, 35, 0, Local, 1321631795},                // Nov 18 6:116:35
+	{2011, 10, 49, 7, 56, 35, 0, Local, 1321631795},                 // Oct 49 7:56:35
+	{2011, 11, 18, 7, 55, 95, 0, Local, 1321631795},                 // Nov 18 7:55:95
+	{2011, 11, 18, 7, 56, 34, 1e9, Local, 1321631795},               // Nov 18 7:56:34 + 10⁹ns
+	{2011, 12, -12, 7, 56, 35, 0, Local, 1321631795},                // Dec -21 7:56:35
+	{2012, 1, -43, 7, 56, 35, 0, Local, 1321631795},                 // Jan -52 7:56:35 2012
+	{2012, int(January - 2), 18, 7, 56, 35, 0, Local, 1321631795},   // (Jan-2) 18 7:56:35 2012
+	{2010, int(December + 11), 18, 7, 56, 35, 0, Local, 1321631795}, // (Dec+11) 18 7:56:35 2010
+}
+
+func TestDate(t *testing.T) {
+	for _, tt := range dateTests {
+		time := Date(tt.year, Month(tt.month), tt.day, tt.hour, tt.min, tt.sec, tt.nsec, tt.z)
+		want := Unix(tt.unix, 0)
+		if !time.Equal(want) {
+			t.Errorf("Date(%d, %d, %d, %d, %d, %d, %d, %s) = %v, want %v",
+				tt.year, tt.month, tt.day, tt.hour, tt.min, tt.sec, tt.nsec, tt.z,
+				time, want)
+		}
+	}
+}
+
+func BenchmarkNow(b *testing.B) {
 	for i := 0; i < b.N; i++ {
-		Nanoseconds()
+		Now()
 	}
 }
 
 func BenchmarkFormat(b *testing.B) {
-	time := SecondsToLocalTime(1265346057)
+	time := Unix(1265346057, 0)
 	for i := 0; i < b.N; i++ {
 		time.Format("Mon Jan  2 15:04:05 2006")
 	}
@@ -564,3 +650,31 @@ func BenchmarkParse(b *testing.B) {
 		Parse(ANSIC, "Mon Jan  2 15:04:05 2006")
 	}
 }
+
+func BenchmarkHour(b *testing.B) {
+	t := Now()
+	for i := 0; i < b.N; i++ {
+		_ = t.Hour()
+	}
+}
+
+func BenchmarkSecond(b *testing.B) {
+	t := Now()
+	for i := 0; i < b.N; i++ {
+		_ = t.Second()
+	}
+}
+
+func BenchmarkYear(b *testing.B) {
+	t := Now()
+	for i := 0; i < b.N; i++ {
+		_ = t.Year()
+	}
+}
+
+func BenchmarkDay(b *testing.B) {
+	t := Now()
+	for i := 0; i < b.N; i++ {
+		_ = t.Day()
+	}
+}
diff --git a/libgo/go/time/zoneinfo.go b/libgo/go/time/zoneinfo.go
new file mode 100644
index 00000000000..aca56e746af
--- /dev/null
+++ b/libgo/go/time/zoneinfo.go
@@ -0,0 +1,191 @@
+// 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 time
+
+import "sync"
+
+// A Location maps time instants to the zone in use at that time.
+// Typically, the Location represents the collection of time offsets
+// in use in a geographical area, such as CEST and CET for central Europe.
+type Location struct {
+	name string
+	zone []zone
+	tx   []zoneTrans
+
+	// Most lookups will be for the current time.
+	// To avoid the binary search through tx, keep a
+	// static one-element cache that gives the correct
+	// zone for the time when the Location was created.
+	// if cacheStart <= t <= cacheEnd,
+	// lookup can return cacheZone.
+	// The units for cacheStart and cacheEnd are seconds
+	// since January 1, 1970 UTC, to match the argument
+	// to lookup.
+	cacheStart int64
+	cacheEnd   int64
+	cacheZone  *zone
+}
+
+// A zone represents a single time zone such as CEST or CET.
+type zone struct {
+	name   string // abbreviated name, "CET"
+	offset int    // seconds east of UTC
+	isDST  bool   // is this zone Daylight Savings Time?
+}
+
+// A zoneTrans represents a single time zone transition.
+type zoneTrans struct {
+	when         int64 // transition time, in seconds since 1970 GMT
+	index        uint8 // the index of the zone that goes into effect at that time
+	isstd, isutc bool  // ignored - no idea what these mean
+}
+
+// UTC represents Universal Coordinated Time (UTC).
+var UTC *Location = &utcLoc
+
+// utcLoc is separate so that get can refer to &utcLoc
+// and ensure that it never returns a nil *Location,
+// even if a badly behaved client has changed UTC.
+var utcLoc = Location{name: "UTC"}
+
+// Local represents the system's local time zone.
+var Local *Location = &localLoc
+
+// localLoc is separate so that initLocal can initialize
+// it even if a client has changed Local.
+var localLoc Location
+var localOnce sync.Once
+
+func (l *Location) get() *Location {
+	if l == nil {
+		return &utcLoc
+	}
+	if l == &localLoc {
+		localOnce.Do(initLocal)
+	}
+	return l
+}
+
+// String returns a descriptive name for the time zone information,
+// corresponding to the argument to LoadLocation.
+func (l *Location) String() string {
+	return l.get().name
+}
+
+// FixedZone returns a Location that always uses
+// the given zone name and offset (seconds east of UTC).
+func FixedZone(name string, offset int) *Location {
+	l := &Location{
+		name:       name,
+		zone:       []zone{{name, offset, false}},
+		tx:         []zoneTrans{{-1 << 63, 0, false, false}},
+		cacheStart: -1 << 63,
+		cacheEnd:   1<<63 - 1,
+	}
+	l.cacheZone = &l.zone[0]
+	return l
+}
+
+// lookup returns information about the time zone in use at an
+// instant in time expressed as seconds since January 1, 1970 00:00:00 UTC.
+//
+// The returned information gives the name of the zone (such as "CET"),
+// the start and end times bracketing sec when that zone is in effect,
+// the offset in seconds east of UTC (such as -5*60*60), and whether
+// the daylight savings is being observed at that time.
+func (l *Location) lookup(sec int64) (name string, offset int, isDST bool, start, end int64) {
+	l = l.get()
+
+	if len(l.tx) == 0 {
+		name = "UTC"
+		offset = 0
+		isDST = false
+		start = -1 << 63
+		end = 1<<63 - 1
+		return
+	}
+
+	if zone := l.cacheZone; zone != nil && l.cacheStart <= sec && sec < l.cacheEnd {
+		name = zone.name
+		offset = zone.offset
+		isDST = zone.isDST
+		start = l.cacheStart
+		end = l.cacheEnd
+		return
+	}
+
+	// Binary search for entry with largest time <= sec.
+	// Not using sort.Search to avoid dependencies.
+	tx := l.tx
+	end = 1<<63 - 1
+	for len(tx) > 1 {
+		m := len(tx) / 2
+		lim := tx[m].when
+		if sec < lim {
+			end = lim
+			tx = tx[0:m]
+		} else {
+			tx = tx[m:]
+		}
+	}
+	zone := &l.zone[tx[0].index]
+	name = zone.name
+	offset = zone.offset
+	isDST = zone.isDST
+	start = tx[0].when
+	// end = maintained during the search
+	return
+}
+
+// lookupName returns information about the time zone with
+// the given name (such as "EST").
+func (l *Location) lookupName(name string) (offset int, isDST bool, ok bool) {
+	l = l.get()
+	for i := range l.zone {
+		zone := &l.zone[i]
+		if zone.name == name {
+			return zone.offset, zone.isDST, true
+		}
+	}
+	return
+}
+
+// lookupOffset returns information about the time zone with
+// the given offset (such as -5*60*60).
+func (l *Location) lookupOffset(offset int) (name string, isDST bool, ok bool) {
+	l = l.get()
+	for i := range l.zone {
+		zone := &l.zone[i]
+		if zone.offset == offset {
+			return zone.name, zone.isDST, true
+		}
+	}
+	return
+}
+
+// NOTE(rsc): Eventually we will need to accept the POSIX TZ environment
+// syntax too, but I don't feel like implementing it today.
+
+// NOTE(rsc): Using the IANA names below means ensuring we have access
+// to the database.  Probably we will ship the files in $GOROOT/lib/zoneinfo/
+// and only look there if there are no system files available (such as on Windows).
+// The files total 200 kB.
+
+// LoadLocation returns the Location with the given name.
+//
+// If the name is "" or "UTC", LoadLocation returns UTC.
+// If the name is "Local", LoadLocation returns Local.
+//
+// Otherwise, the name is taken to be a location name corresponding to a file
+// in the IANA Time Zone database, such as "America/New_York".
+func LoadLocation(name string) (*Location, error) {
+	if name == "" || name == "UTC" {
+		return UTC, nil
+	}
+	if name == "Local" {
+		return Local, nil
+	}
+	return loadLocation(name)
+}
diff --git a/libgo/go/time/zoneinfo_plan9.go b/libgo/go/time/zoneinfo_plan9.go
index 577ef85bd68..38aefc7a977 100644
--- a/libgo/go/time/zoneinfo_plan9.go
+++ b/libgo/go/time/zoneinfo_plan9.go
@@ -6,11 +6,10 @@
 
 package time
 
-import (
-	"os"
-	"strconv"
-	"strings"
-)
+//import (
+//	"strconv"
+//	"strings"
+//)
 
 func parseZones(s string) (zt []zonetime) {
 	f := strings.Fields(s)
@@ -49,7 +48,7 @@ func parseZones(s string) (zt []zonetime) {
 	return
 }
 
-func setupZone() {
+func initLocal() {
 	t, err := os.Getenverror("timezone")
 	if err != nil {
 		// do nothing: use UTC
@@ -58,16 +57,8 @@ func setupZone() {
 	zones = parseZones(t)
 }
 
-func setupTestingZone() {
-	f, err := os.Open("/adm/timezone/US_Pacific")
-	if err != nil {
-		return
-	}
-	defer f.Close()
-	l, _ := f.Seek(0, 2)
-	f.Seek(0, 0)
-	buf := make([]byte, l)
-	_, err = f.Read(buf)
+func initTestingZone() {
+	buf, err := readFile("/adm/timezone/US_Pacific")
 	if err != nil {
 		return
 	}
diff --git a/libgo/go/time/zoneinfo_posix.go b/libgo/go/time/zoneinfo_posix.go
deleted file mode 100644
index b0fa6c33b65..00000000000
--- a/libgo/go/time/zoneinfo_posix.go
+++ /dev/null
@@ -1,64 +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.
-
-// +build darwin freebsd linux openbsd plan9
-
-package time
-
-import "sync"
-
-// Parsed representation
-type zone struct {
-	utcoff int
-	isdst  bool
-	name   string
-}
-
-type zonetime struct {
-	time         int32 // transition time, in seconds since 1970 GMT
-	zone         *zone // the zone that goes into effect at that time
-	isstd, isutc bool  // ignored - no idea what these mean
-}
-
-var zones []zonetime
-var onceSetupZone sync.Once
-
-// Look up the correct time zone (daylight savings or not) for the given unix time, in the current location.
-func lookupTimezone(sec int64) (zone string, offset int) {
-	onceSetupZone.Do(setupZone)
-	if len(zones) == 0 {
-		return "UTC", 0
-	}
-
-	// Binary search for entry with largest time <= sec
-	tz := zones
-	for len(tz) > 1 {
-		m := len(tz) / 2
-		if sec < int64(tz[m].time) {
-			tz = tz[0:m]
-		} else {
-			tz = tz[m:]
-		}
-	}
-	z := tz[0].zone
-	return z.name, z.utcoff
-}
-
-// lookupByName returns the time offset for the
-// time zone with the given abbreviation. It only considers
-// time zones that apply to the current system.
-// For example, for a system configured as being in New York,
-// it only recognizes "EST" and "EDT".
-// For a system in San Francisco, "PST" and "PDT".
-// For a system in Sydney, "EST" and "EDT", though they have
-// different meanings than they do in New York.
-func lookupByName(name string) (off int, found bool) {
-	onceSetupZone.Do(setupZone)
-	for _, z := range zones {
-		if name == z.zone.name {
-			return z.zone.utcoff, true
-		}
-	}
-	return 0, false
-}
diff --git a/libgo/go/time/zoneinfo_unix.go b/libgo/go/time/zoneinfo_unix.go
index b552e589aa9..83d5b983c6e 100644
--- a/libgo/go/time/zoneinfo_unix.go
+++ b/libgo/go/time/zoneinfo_unix.go
@@ -12,8 +12,8 @@
 package time
 
 import (
-	"bytes"
-	"os"
+	"errors"
+	"syscall"
 )
 
 const (
@@ -65,18 +65,20 @@ func byteString(p []byte) string {
 	return string(p)
 }
 
-func parseinfo(bytes []byte) (zt []zonetime, ok bool) {
+var badData = errors.New("malformed time zone information")
+
+func loadZoneData(bytes []byte) (l *Location, err error) {
 	d := data{bytes, false}
 
 	// 4-byte magic "TZif"
 	if magic := d.read(4); string(magic) != "TZif" {
-		return nil, false
+		return nil, badData
 	}
 
 	// 1-byte version, then 15 bytes of padding
 	var p []byte
 	if p = d.read(16); len(p) != 16 || p[0] != 0 && p[0] != '2' {
-		return nil, false
+		return nil, badData
 	}
 
 	// six big-endian 32-bit integers:
@@ -98,7 +100,7 @@ func parseinfo(bytes []byte) (zt []zonetime, ok bool) {
 	for i := 0; i < 6; i++ {
 		nn, ok := d.big4()
 		if !ok {
-			return nil, false
+			return nil, badData
 		}
 		n[i] = int(nn)
 	}
@@ -127,7 +129,7 @@ func parseinfo(bytes []byte) (zt []zonetime, ok bool) {
 	isutc := d.read(n[NUTCLocal])
 
 	if d.error { // ran out of data
-		return nil, false
+		return nil, badData
 	}
 
 	// If version == 2, the entire file repeats, this time using
@@ -137,90 +139,119 @@ func parseinfo(bytes []byte) (zt []zonetime, ok bool) {
 	// Now we can build up a useful data structure.
 	// First the zone information.
 	//	utcoff[4] isdst[1] nameindex[1]
-	z := make([]zone, n[NZone])
-	for i := 0; i < len(z); i++ {
+	zone := make([]zone, n[NZone])
+	for i := range zone {
 		var ok bool
 		var n uint32
 		if n, ok = zonedata.big4(); !ok {
-			return nil, false
+			return nil, badData
 		}
-		z[i].utcoff = int(n)
+		zone[i].offset = int(n)
 		var b byte
 		if b, ok = zonedata.byte(); !ok {
-			return nil, false
+			return nil, badData
 		}
-		z[i].isdst = b != 0
+		zone[i].isDST = b != 0
 		if b, ok = zonedata.byte(); !ok || int(b) >= len(abbrev) {
-			return nil, false
+			return nil, badData
 		}
-		z[i].name = byteString(abbrev[b:])
+		zone[i].name = byteString(abbrev[b:])
 	}
 
 	// Now the transition time info.
-	zt = make([]zonetime, n[NTime])
-	for i := 0; i < len(zt); i++ {
+	tx := make([]zoneTrans, n[NTime])
+	for i := range tx {
 		var ok bool
 		var n uint32
 		if n, ok = txtimes.big4(); !ok {
-			return nil, false
+			return nil, badData
 		}
-		zt[i].time = int32(n)
-		if int(txzones[i]) >= len(z) {
-			return nil, false
+		tx[i].when = int64(int32(n))
+		if int(txzones[i]) >= len(zone) {
+			return nil, badData
 		}
-		zt[i].zone = &z[txzones[i]]
+		tx[i].index = txzones[i]
 		if i < len(isstd) {
-			zt[i].isstd = isstd[i] != 0
+			tx[i].isstd = isstd[i] != 0
 		}
 		if i < len(isutc) {
-			zt[i].isutc = isutc[i] != 0
+			tx[i].isutc = isutc[i] != 0
 		}
 	}
-	return zt, true
+
+	// Commited to succeed.
+	l = &Location{zone: zone, tx: tx}
+
+	// Fill in the cache with information about right now,
+	// since that will be the most common lookup.
+	sec, _ := now()
+	for i := range tx {
+		if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) {
+			l.cacheStart = tx[i].when
+			l.cacheEnd = 1<<63 - 1
+			if i+1 < len(tx) {
+				l.cacheEnd = tx[i+1].when
+			}
+			l.cacheZone = &l.zone[tx[i].index]
+		}
+	}
+
+	return l, nil
 }
 
-func readinfofile(name string) ([]zonetime, bool) {
-	var b bytes.Buffer
-
-	f, err := os.Open(name)
+func loadZoneFile(name string) (l *Location, err error) {
+	buf, err := readFile(name)
 	if err != nil {
-		return nil, false
+		return
 	}
-	defer f.Close()
-	if _, err := b.ReadFrom(f); err != nil {
-		return nil, false
-	}
-	return parseinfo(b.Bytes())
+	return loadZoneData(buf)
 }
 
-func setupTestingZone() {
-	os.Setenv("TZ", "America/Los_Angeles")
-	setupZone()
+func initTestingZone() {
+	syscall.Setenv("TZ", "America/Los_Angeles")
+	initLocal()
 }
 
-func setupZone() {
+// Many systems use /usr/share/zoneinfo, Solaris 2 has
+// /usr/share/lib/zoneinfo, IRIX 6 has /usr/lib/locale/TZ.
+var zoneDirs = []string{
+	"/usr/share/zoneinfo/",
+	"/usr/share/lib/zoneinfo/",
+	"/usr/lib/locale/TZ/",
+}
+
+func initLocal() {
 	// consult $TZ to find the time zone to use.
 	// no $TZ means use the system default /etc/localtime.
 	// $TZ="" means use UTC.
 	// $TZ="foo" means use /usr/share/zoneinfo/foo.
-	// Many systems use /usr/share/zoneinfo, Solaris 2 has
-	// /usr/share/lib/zoneinfo, IRIX 6 has /usr/lib/locale/TZ.
-	zoneDirs := []string{"/usr/share/zoneinfo/",
-		"/usr/share/lib/zoneinfo/",
-		"/usr/lib/locale/TZ/"}
 
-	tz, err := os.Getenverror("TZ")
+	tz, ok := syscall.Getenv("TZ")
 	switch {
-	case err == os.ENOENV:
-		zones, _ = readinfofile("/etc/localtime")
-	case len(tz) > 0:
-		for _, zoneDir := range zoneDirs {
-			var ok bool
-			if zones, ok = readinfofile(zoneDir + tz); ok {
-				break
-			}
+	case !ok:
+		z, err := loadZoneFile("/etc/localtime")
+		if err == nil {
+			localLoc = *z
+			localLoc.name = "Local"
+			return
+		}
+	case tz != "" && tz != "UTC":
+		if z, err := loadLocation(tz); err == nil {
+			localLoc = *z
+			return
 		}
-	case len(tz) == 0:
-		// do nothing: use UTC
 	}
+
+	// Fall back to UTC.
+	localLoc.name = "UTC"
+}
+
+func loadLocation(name string) (*Location, error) {
+	for _, zoneDir := range zoneDirs {
+		if z, err := loadZoneFile(zoneDir + name); err == nil {
+			z.name = name
+			return z, nil
+		}
+	}
+	return nil, errors.New("unknown time zone " + name)
 }
diff --git a/libgo/go/time/zoneinfo_windows.go b/libgo/go/time/zoneinfo_windows.go
index 995fd44dc06..beef4de92b0 100644
--- a/libgo/go/time/zoneinfo_windows.go
+++ b/libgo/go/time/zoneinfo_windows.go
@@ -5,34 +5,21 @@
 package time
 
 import (
-	"os"
-	"sync"
+	"errors"
 	"syscall"
 )
 
-// BUG(brainman): The Windows implementation assumes that
-// this year's rules for daylight savings time apply to all previous
-// and future years as well.
+// TODO(rsc): Fall back to copy of zoneinfo files.
 
-// TODO(brainman): use GetDynamicTimeZoneInformation, whenever possible (Vista and up),
-// to improve on situation described in the bug above.
+// BUG(brainman,rsc): On Windows, the operating system does not provide complete
+// time zone information.
+// The implementation assumes that this year's rules for daylight savings
+// time apply to all previous and future years as well. 
+// Also, time zone abbreviations are unavailable.  The implementation constructs
+// them using the capital letters from a longer time zone description.	
 
-type zone struct {
-	name                  string
-	offset                int
-	year                  int64
-	month, day, dayofweek int
-	hour, minute, second  int
-	abssec                int64
-	prev                  *zone
-}
-
-// BUG(rsc): On Windows, time zone abbreviations are unavailable.
-// This package constructs them using the capital letters from a longer
-// time zone description.
-
-// Populate zone struct with Windows supplied information. Returns true, if data is valid.
-func (z *zone) populate(bias, biasdelta int32, d *syscall.Systemtime, name []uint16) (dateisgood bool) {
+// abbrev returns the abbreviation to use for the given zone name.
+func abbrev(name []uint16) string {
 	// name is 'Pacific Standard Time' but we want 'PST'.
 	// Extract just capital letters.  It's not perfect but the
 	// information we need is not available from the kernel.
@@ -41,147 +28,101 @@ func (z *zone) populate(bias, biasdelta int32, d *syscall.Systemtime, name []uin
 	//
 	// http://social.msdn.microsoft.com/Forums/eu/vclanguage/thread/a87e1d25-fb71-4fe0-ae9c-a9578c9753eb
 	// http://stackoverflow.com/questions/4195948/windows-time-zone-abbreviations-in-asp-net
-	short := make([]uint16, len(name))
-	w := 0
+	var short []rune
 	for _, c := range name {
 		if 'A' <= c && c <= 'Z' {
-			short[w] = c
-			w++
+			short = append(short, rune(c))
 		}
 	}
-	z.name = syscall.UTF16ToString(short[:w])
-
-	z.offset = int(bias)
-	z.year = int64(d.Year)
-	z.month = int(d.Month)
-	z.day = int(d.Day)
-	z.dayofweek = int(d.DayOfWeek)
-	z.hour = int(d.Hour)
-	z.minute = int(d.Minute)
-	z.second = int(d.Second)
-	dateisgood = d.Month != 0
-	if dateisgood {
-		z.offset += int(biasdelta)
-	}
-	z.offset = -z.offset * 60
-	return
+	return string(short)
 }
 
-// Pre-calculate cutoff time in seconds since the Unix epoch, if data is supplied in "absolute" format.
-func (z *zone) preCalculateAbsSec() {
-	if z.year != 0 {
-		t := &Time{
-			Year:   z.year,
-			Month:  int(z.month),
-			Day:    int(z.day),
-			Hour:   int(z.hour),
-			Minute: int(z.minute),
-			Second: int(z.second),
-		}
-		z.abssec = t.Seconds()
-		// Time given is in "local" time. Adjust it for "utc".
-		z.abssec -= int64(z.prev.offset)
-	}
-}
-
-// Convert zone cutoff time to sec in number of seconds since the Unix epoch, given particular year.
-func (z *zone) cutoffSeconds(year int64) int64 {
+// pseudoUnix returns the pseudo-Unix time (seconds since Jan 1 1970 *LOCAL TIME*)
+// denoted by the system date+time d in the given year.
+// It is up to the caller to convert this local time into a UTC-based time.
+func pseudoUnix(year int, d *syscall.Systemtime) int64 {
 	// Windows specifies daylight savings information in "day in month" format:
-	// z.month is month number (1-12)
-	// z.dayofweek is appropriate weekday (Sunday=0 to Saturday=6)
-	// z.day is week within the month (1 to 5, where 5 is last week of the month)
-	// z.hour, z.minute and z.second are absolute time
-	t := &Time{
-		Year:   year,
-		Month:  int(z.month),
-		Day:    1,
-		Hour:   int(z.hour),
-		Minute: int(z.minute),
-		Second: int(z.second),
-	}
-	t = SecondsToUTC(t.Seconds())
-	i := int(z.dayofweek) - t.Weekday()
+	// d.Month is month number (1-12)
+	// d.DayOfWeek is appropriate weekday (Sunday=0 to Saturday=6)
+	// d.Day is week within the month (1 to 5, where 5 is last week of the month)
+	// d.Hour, d.Minute and d.Second are absolute time
+	day := 1
+	t := Date(year, Month(d.Month), day, int(d.Hour), int(d.Minute), int(d.Second), 0, UTC)
+	i := int(d.DayOfWeek) - int(t.Weekday())
 	if i < 0 {
 		i += 7
 	}
-	t.Day += i
-	if week := int(z.day) - 1; week < 4 {
-		t.Day += week * 7
+	day += i
+	if week := int(d.Day) - 1; week < 4 {
+		day += week * 7
 	} else {
 		// "Last" instance of the day.
-		t.Day += 4 * 7
-		if t.Day > months(year)[t.Month] {
-			t.Day -= 7
+		day += 4 * 7
+		if day > daysIn(Month(d.Month), year) {
+			day -= 7
 		}
 	}
-	// Result is in "local" time. Adjust it for "utc".
-	return t.Seconds() - int64(z.prev.offset)
+	return t.sec + int64(day-1)*secondsPerDay + internalToUnix
 }
 
-// Is t before the cutoff for switching to z?
-func (z *zone) isBeforeCutoff(t *Time) bool {
-	var coff int64
-	if z.year == 0 {
-		// "day in month" format used
-		coff = z.cutoffSeconds(t.Year)
-	} else {
-		// "absolute" format used
-		coff = z.abssec
+func initLocalFromTZI(i *syscall.Timezoneinformation) {
+	l := &localLoc
+
+	nzone := 1
+	if i.StandardDate.Month > 0 {
+		nzone++
 	}
-	return t.Seconds() < coff
-}
+	l.zone = make([]zone, nzone)
 
-type zoneinfo struct {
-	disabled         bool // daylight saving time is not used locally
-	offsetIfDisabled int
-	januaryIsStd     bool // is january 1 standard time?
-	std, dst         zone
-}
-
-// Pick zone (std or dst) t time belongs to.
-func (zi *zoneinfo) pickZone(t *Time) *zone {
-	z := &zi.std
-	if tz.januaryIsStd {
-		if !zi.dst.isBeforeCutoff(t) && zi.std.isBeforeCutoff(t) {
-			// after switch to daylight time and before the switch back to standard
-			z = &zi.dst
-		}
-	} else {
-		if zi.std.isBeforeCutoff(t) || !zi.dst.isBeforeCutoff(t) {
-			// before switch to standard time or after the switch back to daylight
-			z = &zi.dst
-		}
-	}
-	return z
-}
-
-var tz zoneinfo
-var initError error
-var onceSetupZone sync.Once
-
-func setupZone() {
-	var i syscall.Timezoneinformation
-	if _, e := syscall.GetTimeZoneInformation(&i); e != nil {
-		initError = os.NewSyscallError("GetTimeZoneInformation", e)
+	std := &l.zone[0]
+	std.name = abbrev(i.StandardName[0:])
+	if nzone == 1 {
+		// No daylight savings.
+		std.offset = -int(i.Bias) * 60
+		l.cacheStart = -1 << 63
+		l.cacheEnd = 1<<63 - 1
+		l.cacheZone = std
 		return
 	}
-	setupZoneFromTZI(&i)
-}
 
-func setupZoneFromTZI(i *syscall.Timezoneinformation) {
-	if !tz.std.populate(i.Bias, i.StandardBias, &i.StandardDate, i.StandardName[0:]) {
-		tz.disabled = true
-		tz.offsetIfDisabled = tz.std.offset
-		return
+	// StandardBias must be ignored if StandardDate is not set,
+	// so this computation is delayed until after the nzone==1
+	// return above.
+	std.offset = -int(i.Bias+i.StandardBias) * 60
+
+	dst := &l.zone[1]
+	dst.name = abbrev(i.DaylightName[0:])
+	dst.offset = -int(i.Bias+i.DaylightBias) * 60
+	dst.isDST = true
+
+	// Arrange so that d0 is first transition date, d1 second,
+	// i0 is index of zone after first transition, i1 second.
+	d0 := &i.StandardDate
+	d1 := &i.DaylightDate
+	i0 := 0
+	i1 := 1
+	if d0.Month > d1.Month {
+		d0, d1 = d1, d0
+		i0, i1 = i1, i0
+	}
+
+	// 2 tx per year, 100 years on each side of this year
+	l.tx = make([]zoneTrans, 400)
+
+	t := Now().UTC()
+	year := t.Year()
+	txi := 0
+	for y := year - 100; y < year+100; y++ {
+		tx := &l.tx[txi]
+		tx.when = pseudoUnix(y, d0) - int64(l.zone[i1].offset)
+		tx.index = uint8(i0)
+		txi++
+
+		tx = &l.tx[txi]
+		tx.when = pseudoUnix(y, d1) - int64(l.zone[i0].offset)
+		tx.index = uint8(i1)
+		txi++
 	}
-	tz.std.prev = &tz.dst
-	tz.dst.populate(i.Bias, i.DaylightBias, &i.DaylightDate, i.DaylightName[0:])
-	tz.dst.prev = &tz.std
-	tz.std.preCalculateAbsSec()
-	tz.dst.preCalculateAbsSec()
-	// Is january 1 standard time this year?
-	t := UTC()
-	tz.januaryIsStd = tz.dst.cutoffSeconds(t.Year) < tz.std.cutoffSeconds(t.Year)
 }
 
 var usPacific = syscall.Timezoneinformation{
@@ -197,53 +138,20 @@ var usPacific = syscall.Timezoneinformation{
 	DaylightBias: -60,
 }
 
-func setupTestingZone() {
-	setupZoneFromTZI(&usPacific)
+func initTestingZone() {
+	initLocalFromTZI(&usPacific)
 }
 
-// Look up the correct time zone (daylight savings or not) for the given unix time, in the current location.
-func lookupTimezone(sec int64) (zone string, offset int) {
-	onceSetupZone.Do(setupZone)
-	if initError != nil {
-		return "", 0
+func initLocal() {
+	var i syscall.Timezoneinformation
+	if _, err := syscall.GetTimeZoneInformation(&i); err != nil {
+		localLoc.name = "UTC"
+		return
 	}
-	if tz.disabled {
-		return "", tz.offsetIfDisabled
-	}
-	t := SecondsToUTC(sec)
-	z := &tz.std
-	if tz.std.year == 0 {
-		// "day in month" format used
-		z = tz.pickZone(t)
-	} else {
-		// "absolute" format used
-		if tz.std.year == t.Year {
-			// we have rule for the year in question
-			z = tz.pickZone(t)
-		} else {
-			// we do not have any information for that year,
-			// will assume standard offset all year around
-		}
-	}
-	return z.name, z.offset
+	initLocalFromTZI(&i)
 }
 
-// lookupByName returns the time offset for the
-// time zone with the given abbreviation. It only considers
-// time zones that apply to the current system.
-func lookupByName(name string) (off int, found bool) {
-	onceSetupZone.Do(setupZone)
-	if initError != nil {
-		return 0, false
-	}
-	if tz.disabled {
-		return tz.offsetIfDisabled, false
-	}
-	switch name {
-	case tz.std.name:
-		return tz.std.offset, true
-	case tz.dst.name:
-		return tz.dst.offset, true
-	}
-	return 0, false
+// TODO(rsc): Implement.
+func loadLocation(name string) (*Location, error) {
+	return nil, errors.New("unknown time zone " + name)
 }
diff --git a/libgo/go/websocket/client.go b/libgo/go/websocket/client.go
index 5dfd824e6e5..89cdcda71ae 100644
--- a/libgo/go/websocket/client.go
+++ b/libgo/go/websocket/client.go
@@ -72,8 +72,8 @@ A trivial example client:
 	package main
 
 	import (
-		"http"
 		"log"
+		"net/http"
 		"strings"
 		"websocket"
 	)
diff --git a/libgo/go/websocket/hixie.go b/libgo/go/websocket/hixie.go
index 4d5360ff4b9..ec7b7ae0a45 100644
--- a/libgo/go/websocket/hixie.go
+++ b/libgo/go/websocket/hixie.go
@@ -274,7 +274,7 @@ func getChallengeResponse(number1, number2 uint32, key3 []byte) (expected []byte
 	if _, err = h.Write(challenge); err != nil {
 		return
 	}
-	expected = h.Sum()
+	expected = h.Sum(nil)
 	return
 }
 
diff --git a/libgo/go/websocket/hybi.go b/libgo/go/websocket/hybi.go
index b17d9470bbc..ff386dc7f21 100644
--- a/libgo/go/websocket/hybi.go
+++ b/libgo/go/websocket/hybi.go
@@ -371,7 +371,7 @@ func getNonceAccept(nonce []byte) (expected []byte, err error) {
 		return
 	}
 	expected = make([]byte, 28)
-	base64.StdEncoding.Encode(expected, h.Sum())
+	base64.StdEncoding.Encode(expected, h.Sum(nil))
 	return
 }
 
diff --git a/libgo/go/websocket/server.go b/libgo/go/websocket/server.go
index 57dc4fd1dff..8320b032ead 100644
--- a/libgo/go/websocket/server.go
+++ b/libgo/go/websocket/server.go
@@ -60,8 +60,8 @@ A trivial example server:
 	package main
 
 	import (
-		"http"
 		"io"
+		"net/http"
 		"websocket"
 	)
 
diff --git a/libgo/runtime/go-nanotime.c b/libgo/runtime/go-nanotime.c
index 197fb15d2a5..7e5e3e098a9 100644
--- a/libgo/runtime/go-nanotime.c
+++ b/libgo/runtime/go-nanotime.c
@@ -6,17 +6,16 @@
 
 #include <sys/time.h>
 
-#include "go-assert.h"
 #include "runtime.h"
 
+int64 runtime_nanotime (void)
+  __attribute__ ((no_split_stack));
+
 int64
 runtime_nanotime (void)
 {
-  int i;
   struct timeval tv;
 
-  i = gettimeofday (&tv, NULL);
-  __go_assert (i == 0);
-
+  gettimeofday (&tv, NULL);
   return (int64) tv.tv_sec * 1000000000 + (int64) tv.tv_usec * 1000;
 }
diff --git a/libgo/runtime/go-now.c b/libgo/runtime/go-now.c
new file mode 100644
index 00000000000..5df8085c6a8
--- /dev/null
+++ b/libgo/runtime/go-now.c
@@ -0,0 +1,31 @@
+// 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.
+
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/time.h>
+
+// Return current time.  This is the implementation of time.now().
+
+struct time_now_ret
+{
+  int64_t sec;
+  int32_t nsec;
+};
+
+struct time_now_ret now()
+  __asm__ ("libgo_time.time.now")
+  __attribute__ ((no_split_stack));
+
+struct time_now_ret
+now()
+{
+  struct timeval tv;
+  struct time_now_ret ret;
+
+  gettimeofday (&tv, NULL);
+  ret.sec = tv.tv_sec;
+  ret.nsec = tv.tv_usec * 1000;
+  return ret;
+}
diff --git a/libgo/runtime/time.goc b/libgo/runtime/time.goc
index 93b896ed0d2..cae15e5946a 100644
--- a/libgo/runtime/time.goc
+++ b/libgo/runtime/time.goc
@@ -18,10 +18,7 @@ static bool deltimer(Timer*);
 // Package time APIs.
 // Godoc uses the comments in package time, not these.
 
-// Nanoseconds returns the current time in nanoseconds.
-func Nanoseconds() (ret int64) {
-	ret = runtime_nanotime();
-}
+// time.now is implemented in assembly.
 
 // Sleep puts the current goroutine to sleep for at least ns nanoseconds.
 func Sleep(ns int64) {