]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libgo: Update to weekly.2012-02-07.
authorIan Lance Taylor <ian@gcc.gnu.org>
Thu, 9 Feb 2012 08:19:58 +0000 (08:19 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Thu, 9 Feb 2012 08:19:58 +0000 (08:19 +0000)
From-SVN: r184034

294 files changed:
gcc/testsuite/go.test/test/chan/select2.go
gcc/testsuite/go.test/test/gc2.go
gcc/testsuite/go.test/test/malloc1.go
gcc/testsuite/go.test/test/mallocrand.go
gcc/testsuite/go.test/test/mallocrep.go
gcc/testsuite/go.test/test/mallocrep1.go
libgo/MERGE
libgo/Makefile.am
libgo/Makefile.in
libgo/go/archive/zip/reader.go
libgo/go/archive/zip/reader_test.go
libgo/go/archive/zip/struct.go
libgo/go/archive/zip/testdata/symlink.zip [new file with mode: 0644]
libgo/go/archive/zip/writer.go
libgo/go/archive/zip/writer_test.go
libgo/go/archive/zip/zip_test.go
libgo/go/bufio/bufio.go
libgo/go/bufio/bufio_test.go
libgo/go/bytes/buffer.go
libgo/go/compress/flate/deflate.go
libgo/go/compress/flate/deflate_test.go
libgo/go/compress/flate/huffman_code.go
libgo/go/compress/lzw/reader_test.go
libgo/go/compress/zlib/writer_test.go
libgo/go/crypto/cipher/cbc.go
libgo/go/crypto/cipher/io.go
libgo/go/crypto/cipher/ocfb.go [deleted file]
libgo/go/crypto/cipher/ocfb_test.go [deleted file]
libgo/go/crypto/crypto.go
libgo/go/crypto/des/cipher.go
libgo/go/crypto/dsa/dsa.go
libgo/go/crypto/elliptic/elliptic_test.go
libgo/go/crypto/elliptic/p224.go
libgo/go/crypto/rand/util.go
libgo/go/crypto/rsa/pkcs1v15.go
libgo/go/crypto/rsa/rsa.go
libgo/go/crypto/tls/handshake_client.go
libgo/go/crypto/tls/tls.go
libgo/go/crypto/x509/pkcs1.go
libgo/go/crypto/x509/pkix/pkix.go
libgo/go/crypto/x509/verify.go
libgo/go/crypto/x509/verify_test.go
libgo/go/crypto/x509/x509.go
libgo/go/database/sql/convert.go
libgo/go/database/sql/convert_test.go
libgo/go/database/sql/driver/driver.go
libgo/go/database/sql/fakedb_test.go
libgo/go/database/sql/sql.go
libgo/go/encoding/asn1/marshal.go
libgo/go/encoding/base32/base32.go
libgo/go/encoding/base32/base32_test.go
libgo/go/encoding/base64/base64.go
libgo/go/encoding/base64/base64_test.go
libgo/go/encoding/binary/binary.go
libgo/go/encoding/binary/binary_test.go
libgo/go/encoding/csv/reader.go
libgo/go/encoding/gob/codec_test.go
libgo/go/encoding/gob/debug.go
libgo/go/encoding/gob/decode.go
libgo/go/encoding/gob/decoder.go
libgo/go/encoding/gob/doc.go
libgo/go/encoding/gob/encoder_test.go
libgo/go/encoding/gob/error.go
libgo/go/encoding/gob/timing_test.go
libgo/go/encoding/gob/type.go
libgo/go/encoding/hex/hex.go
libgo/go/encoding/hex/hex_test.go
libgo/go/encoding/json/decode_test.go
libgo/go/encoding/json/encode.go
libgo/go/encoding/json/encode_test.go
libgo/go/encoding/json/scanner.go
libgo/go/encoding/pem/pem.go
libgo/go/encoding/pem/pem_test.go
libgo/go/encoding/xml/marshal_test.go
libgo/go/encoding/xml/read.go
libgo/go/encoding/xml/typeinfo.go
libgo/go/exp/ebnflint/doc.go
libgo/go/exp/ebnflint/ebnflint.go
libgo/go/exp/html/escape.go
libgo/go/exp/html/parse_test.go
libgo/go/exp/html/token.go
libgo/go/exp/html/token_test.go
libgo/go/exp/inotify/inotify_linux.go
libgo/go/exp/norm/composition.go
libgo/go/exp/norm/forminfo.go
libgo/go/exp/norm/input.go
libgo/go/exp/norm/maketables.go
libgo/go/exp/norm/normalize.go
libgo/go/exp/norm/normalize_test.go
libgo/go/exp/norm/tables.go
libgo/go/exp/signal/signal.go [moved from libgo/go/os/signal/signal.go with 100% similarity]
libgo/go/exp/signal/signal_test.go [moved from libgo/go/os/signal/signal_test.go with 73% similarity]
libgo/go/exp/types/gcimporter_test.go
libgo/go/expvar/expvar.go
libgo/go/expvar/expvar_test.go
libgo/go/flag/flag.go
libgo/go/flag/flag_test.go
libgo/go/fmt/fmt_test.go
libgo/go/fmt/scan.go
libgo/go/go/build/build_test.go
libgo/go/go/build/dir.go
libgo/go/go/doc/comment.go
libgo/go/go/doc/comment_test.go
libgo/go/go/doc/doc.go
libgo/go/go/doc/doc_test.go
libgo/go/go/doc/example.go
libgo/go/go/doc/exports.go
libgo/go/go/doc/reader.go
libgo/go/go/doc/testdata/a.2.golden [new file with mode: 0644]
libgo/go/go/doc/testdata/b.2.golden [new file with mode: 0644]
libgo/go/go/doc/testdata/c.2.golden [new file with mode: 0644]
libgo/go/go/doc/testdata/d.2.golden [new file with mode: 0644]
libgo/go/go/doc/testdata/e.0.golden
libgo/go/go/doc/testdata/e.1.golden
libgo/go/go/doc/testdata/e.2.golden [new file with mode: 0644]
libgo/go/go/doc/testdata/e.go
libgo/go/go/doc/testdata/f.0.golden [new file with mode: 0644]
libgo/go/go/doc/testdata/f.1.golden [new file with mode: 0644]
libgo/go/go/doc/testdata/f.2.golden [new file with mode: 0644]
libgo/go/go/doc/testdata/f.go [new file with mode: 0644]
libgo/go/go/doc/testdata/testing.2.golden [new file with mode: 0644]
libgo/go/go/printer/nodes.go
libgo/go/go/printer/printer.go
libgo/go/go/printer/printer_test.go
libgo/go/go/printer/testdata/parser.go
libgo/go/go/scanner/scanner.go
libgo/go/go/scanner/scanner_test.go
libgo/go/go/token/serialize.go
libgo/go/go/token/serialize_test.go
libgo/go/html/escape.go
libgo/go/html/template/escape_test.go
libgo/go/html/template/js.go
libgo/go/image/bmp/reader.go [deleted file]
libgo/go/image/decode_test.go
libgo/go/image/draw/bench_test.go
libgo/go/image/draw/draw_test.go
libgo/go/image/format.go
libgo/go/image/gif/reader.go
libgo/go/image/image.go
libgo/go/image/jpeg/reader.go
libgo/go/image/jpeg/writer.go
libgo/go/image/jpeg/writer_test.go
libgo/go/image/names.go
libgo/go/image/png/reader.go
libgo/go/image/png/writer.go
libgo/go/image/png/writer_test.go
libgo/go/image/testdata/video-001.bmp [deleted file]
libgo/go/image/testdata/video-001.tiff [deleted file]
libgo/go/image/tiff/buffer.go [deleted file]
libgo/go/image/tiff/buffer_test.go [deleted file]
libgo/go/image/tiff/compress.go [deleted file]
libgo/go/image/tiff/consts.go [deleted file]
libgo/go/image/tiff/reader.go [deleted file]
libgo/go/image/tiff/reader_test.go [deleted file]
libgo/go/image/tiff/testdata/bw-deflate.tiff [deleted file]
libgo/go/image/tiff/testdata/bw-packbits.tiff [deleted file]
libgo/go/image/tiff/testdata/bw-uncompressed.tiff [deleted file]
libgo/go/image/tiff/testdata/no_rps.tiff [deleted file]
libgo/go/image/tiff/testdata/video-001-uncompressed.tiff [deleted file]
libgo/go/io/io.go
libgo/go/io/ioutil/ioutil.go
libgo/go/io/pipe.go
libgo/go/math/acosh.go
libgo/go/math/asinh.go
libgo/go/math/atan2.go
libgo/go/math/atanh.go
libgo/go/math/big/arith.go
libgo/go/math/big/int.go
libgo/go/math/big/int_test.go
libgo/go/math/big/nat.go
libgo/go/math/big/rat.go
libgo/go/math/cbrt.go
libgo/go/math/dim.go
libgo/go/math/erf.go
libgo/go/math/exp.go
libgo/go/math/expm1.go
libgo/go/math/floor.go
libgo/go/math/frexp.go
libgo/go/math/gamma.go
libgo/go/math/hypot.go
libgo/go/math/j0.go
libgo/go/math/j1.go
libgo/go/math/jn.go
libgo/go/math/ldexp.go
libgo/go/math/lgamma.go
libgo/go/math/log.go
libgo/go/math/log1p.go
libgo/go/math/logb.go
libgo/go/math/mod.go
libgo/go/math/nextafter.go
libgo/go/math/pow.go
libgo/go/math/remainder.go
libgo/go/math/sin.go
libgo/go/math/sincos.go
libgo/go/math/sqrt.go
libgo/go/math/tan.go
libgo/go/mime/multipart/multipart.go
libgo/go/net/dial_test.go
libgo/go/net/dnsconfig.go
libgo/go/net/dnsmsg.go
libgo/go/net/fd.go
libgo/go/net/fd_linux.go
libgo/go/net/fd_netbsd.go
libgo/go/net/fd_openbsd.go
libgo/go/net/fd_windows.go
libgo/go/net/file.go
libgo/go/net/http/cgi/host.go
libgo/go/net/http/client.go
libgo/go/net/http/fcgi/fcgi.go
libgo/go/net/http/fs_test.go
libgo/go/net/http/httputil/dump.go
libgo/go/net/http/httputil/persist.go
libgo/go/net/http/httputil/reverseproxy.go
libgo/go/net/http/httputil/reverseproxy_test.go
libgo/go/net/http/request.go
libgo/go/net/http/response.go
libgo/go/net/http/serve_test.go
libgo/go/net/http/server.go
libgo/go/net/http/transport.go
libgo/go/net/http/transport_test.go
libgo/go/net/interface_bsd.go
libgo/go/net/interface_darwin.go
libgo/go/net/interface_freebsd.go
libgo/go/net/interface_linux.go
libgo/go/net/interface_windows.go
libgo/go/net/iprawsock_plan9.go
libgo/go/net/ipsock.go
libgo/go/net/ipsock_plan9.go
libgo/go/net/lookup_windows.go
libgo/go/net/multicast_test.go
libgo/go/net/net.go
libgo/go/net/net_test.go
libgo/go/net/newpollserver.go
libgo/go/net/rpc/client.go
libgo/go/net/rpc/server_test.go
libgo/go/net/sendfile_linux.go
libgo/go/net/smtp/smtp.go
libgo/go/net/sock.go
libgo/go/net/sock_bsd.go
libgo/go/net/sock_linux.go
libgo/go/net/sock_windows.go
libgo/go/net/sockopt.go
libgo/go/net/sockopt_bsd.go
libgo/go/net/sockopt_linux.go
libgo/go/net/sockopt_windows.go
libgo/go/net/sockoptip_windows.go
libgo/go/net/tcpsock_plan9.go
libgo/go/net/tcpsock_posix.go
libgo/go/net/udpsock_plan9.go
libgo/go/net/udpsock_posix.go
libgo/go/net/unixsock_plan9.go
libgo/go/net/unixsock_posix.go
libgo/go/net/url/url.go
libgo/go/old/template/template_test.go
libgo/go/os/exec.go
libgo/go/os/exec/exec_test.go
libgo/go/os/exec_posix.go
libgo/go/os/exec_windows.go
libgo/go/os/file_unix.go
libgo/go/os/getwd.go
libgo/go/os/os_test.go
libgo/go/os/os_unix_test.go
libgo/go/os/stat.go
libgo/go/os/stat_openbsd.go
libgo/go/os/stat_plan9.go
libgo/go/os/types.go
libgo/go/os/user/lookup_stubs.go
libgo/go/os/user/lookup_unix.go
libgo/go/os/user/lookup_windows.go [new file with mode: 0644]
libgo/go/os/user/user.go
libgo/go/os/user/user_test.go
libgo/go/path/filepath/path_test.go
libgo/go/reflect/all_test.go
libgo/go/reflect/type.go
libgo/go/regexp/syntax/parse.go
libgo/go/runtime/gc_test.go
libgo/go/runtime/mem.go
libgo/go/runtime/pprof/pprof.go
libgo/go/strconv/itoa_test.go
libgo/go/strings/example_test.go [new file with mode: 0644]
libgo/go/syscall/env_plan9.go
libgo/go/syscall/exec_unix.go
libgo/go/syscall/exec_windows.go
libgo/go/syscall/security_windows.go [new file with mode: 0644]
libgo/go/syscall/syscall.go
libgo/go/testing/testing.go
libgo/go/text/tabwriter/tabwriter.go
libgo/go/unicode/casetables.go
libgo/go/unicode/tables.go
libgo/runtime/malloc.h
libgo/runtime/mgc0.c
libgo/runtime/proc.c
libgo/runtime/runtime.c
libgo/runtime/runtime.h

index e24c51ed16c2b7b932d6b08b662644c2c80a3b61..2cbb86ec626c72390965b8e2db8405368608028b 100644 (file)
@@ -35,14 +35,17 @@ func main() {
        go sender(c, 100000)
        receiver(c, dummy, 100000)
        runtime.GC()
-       runtime.MemStats.Alloc = 0
+       memstats := new(runtime.MemStats)
+       runtime.ReadMemStats(memstats)
+       alloc := memstats.Alloc
 
        // second time shouldn't increase footprint by much
        go sender(c, 100000)
        receiver(c, dummy, 100000)
        runtime.GC()
+       runtime.ReadMemStats(memstats)
 
-       if runtime.MemStats.Alloc > 1e5 {
-               println("BUG: too much memory for 100,000 selects:", runtime.MemStats.Alloc)
+       if memstats.Alloc-alloc > 1e5 {
+               println("BUG: too much memory for 100,000 selects:", memstats.Alloc-alloc)
        }
 }
index c54d807df724ff0d0f254fd30568fff6b091b8fe..772f9810daaba053c60da480ede9e01b7874a531 100644 (file)
@@ -19,7 +19,9 @@ import (
 
 func main() {
        const N = 10000
-       st := runtime.MemStats
+       st := new(runtime.MemStats)
+       memstats := new(runtime.MemStats)
+       runtime.ReadMemStats(st)
        for i := 0; i < N; i++ {
                c := make(chan int, 10)
                _ = c
@@ -33,8 +35,8 @@ func main() {
                }
        }
 
-       runtime.UpdateMemStats()
-       obj := runtime.MemStats.HeapObjects - st.HeapObjects
+       runtime.ReadMemStats(memstats)
+       obj := memstats.HeapObjects - st.HeapObjects
        if obj > N/5 {
                fmt.Println("too many objects left:", obj)
                os.Exit(1)
index 61f1797c75d43338c60ade64229959ec41099ce0..0f7f0b267a035ca1a1384f1beaac4dcec5ac1d00 100644 (file)
@@ -17,9 +17,10 @@ import (
 var chatty = flag.Bool("v", false, "chatty")
 
 func main() {
+       memstats := new(runtime.MemStats)
        runtime.Free(runtime.Alloc(1))
-       runtime.UpdateMemStats()
+       runtime.ReadMemStats(memstats)
        if *chatty {
-               fmt.Printf("%+v %v\n", runtime.MemStats, uint64(0))
+               fmt.Printf("%+v %v\n", memstats, uint64(0))
        }
 }
index 726e36799a82b104e54bd6d995958de49686cdff..69d07cec5d2f93b2941c8782abf0da0dcac804ee 100644 (file)
@@ -21,8 +21,9 @@ var footprint uint64
 var allocated uint64
 
 func bigger() {
-       runtime.UpdateMemStats()
-       if f := runtime.MemStats.Sys; footprint < f {
+       memstats := new(runtime.MemStats)
+       runtime.ReadMemStats(memstats)
+       if f := memstats.Sys; footprint < f {
                footprint = f
                if *chatty {
                        println("Footprint", footprint, " for ", allocated)
index cffcd1638fcecface8e3002b76fc6b978a73d5bc..4188da9b833519c1b8d46608567a81a616857336 100644 (file)
@@ -16,10 +16,12 @@ import (
 var chatty = flag.Bool("v", false, "chatty")
 
 var oldsys uint64
+var memstats runtime.MemStats
 
 func bigger() {
-       runtime.UpdateMemStats()
-       if st := runtime.MemStats; oldsys < st.Sys {
+       st := &memstats
+       runtime.ReadMemStats(st)
+       if oldsys < st.Sys {
                oldsys = st.Sys
                if *chatty {
                        println(st.Sys, " system bytes for ", st.Alloc, " Go bytes")
@@ -32,26 +34,26 @@ func bigger() {
 }
 
 func main() {
-       runtime.GC()               // clean up garbage from init
-       runtime.UpdateMemStats()   // first call can do some allocations
-       runtime.MemProfileRate = 0 // disable profiler
-       runtime.MemStats.Alloc = 0 // ignore stacks
+       runtime.GC()                    // clean up garbage from init
+       runtime.ReadMemStats(&memstats) // first call can do some allocations
+       runtime.MemProfileRate = 0      // disable profiler
+       stacks := memstats.Alloc        // ignore stacks
        flag.Parse()
        for i := 0; i < 1<<7; i++ {
                for j := 1; j <= 1<<22; j <<= 1 {
                        if i == 0 && *chatty {
                                println("First alloc:", j)
                        }
-                       if a := runtime.MemStats.Alloc; a != 0 {
+                       if a := memstats.Alloc - stacks; a != 0 {
                                println("no allocations but stats report", a, "bytes allocated")
                                panic("fail")
                        }
                        b := runtime.Alloc(uintptr(j))
-                       runtime.UpdateMemStats()
-                       during := runtime.MemStats.Alloc
+                       runtime.ReadMemStats(&memstats)
+                       during := memstats.Alloc - stacks
                        runtime.Free(b)
-                       runtime.UpdateMemStats()
-                       if a := runtime.MemStats.Alloc; a != 0 {
+                       runtime.ReadMemStats(&memstats)
+                       if a := memstats.Alloc - stacks; a != 0 {
                                println("allocated ", j, ": wrong stats: during=", during, " after=", a, " (want 0)")
                                panic("fail")
                        }
index 0b1479900e69805222f4bfad0e84516df669ea3b..f9d7286efd9d3a8aa59c64d701db484799ce598c 100644 (file)
@@ -20,7 +20,7 @@ var reverse = flag.Bool("r", false, "reverse")
 var longtest = flag.Bool("l", false, "long test")
 
 var b []*byte
-var stats = &runtime.MemStats
+var stats = new(runtime.MemStats)
 
 func OkAmount(size, n uintptr) bool {
        if n < size {
@@ -42,7 +42,7 @@ func AllocAndFree(size, count int) {
        if *chatty {
                fmt.Printf("size=%d count=%d ...\n", size, count)
        }
-       runtime.UpdateMemStats()
+       runtime.ReadMemStats(stats)
        n1 := stats.Alloc
        for i := 0; i < count; i++ {
                b[i] = runtime.Alloc(uintptr(size))
@@ -51,13 +51,13 @@ func AllocAndFree(size, count int) {
                        println("lookup failed: got", base, n, "for", b[i])
                        panic("fail")
                }
-               runtime.UpdateMemStats()
+               runtime.ReadMemStats(stats)
                if stats.Sys > 1e9 {
                        println("too much memory allocated")
                        panic("fail")
                }
        }
-       runtime.UpdateMemStats()
+       runtime.ReadMemStats(stats)
        n2 := stats.Alloc
        if *chatty {
                fmt.Printf("size=%d count=%d stats=%+v\n", size, count, *stats)
@@ -75,17 +75,17 @@ func AllocAndFree(size, count int) {
                        panic("fail")
                }
                runtime.Free(b[i])
-               runtime.UpdateMemStats()
+               runtime.ReadMemStats(stats)
                if stats.Alloc != uint64(alloc-n) {
                        println("free alloc got", stats.Alloc, "expected", alloc-n, "after free of", n)
                        panic("fail")
                }
-               if runtime.MemStats.Sys > 1e9 {
+               if stats.Sys > 1e9 {
                        println("too much memory allocated")
                        panic("fail")
                }
        }
-       runtime.UpdateMemStats()
+       runtime.ReadMemStats(stats)
        n4 := stats.Alloc
 
        if *chatty {
index b9b249315a6d2854301bcf9b65ae57a26701ee77..569aa9c8f93e25f7499138601f453a9450b9f66a 100644 (file)
@@ -1,4 +1,4 @@
-1107a7d3cb07
+52ba9506bd99
 
 The first line of this file holds the Mercurial revision number of the
 last merge done from the master library sources.
index bb70b0f8aef867953959d22a48085b9ce4407600..300d16bf263f3266cb7c8d01f4fa95372caf335d 100644 (file)
@@ -226,6 +226,7 @@ toolexeclibgoexp_DATA = \
        $(exp_inotify_gox) \
        exp/norm.gox \
        exp/proxy.gox \
+       exp/signal.gox \
        exp/terminal.gox \
        exp/types.gox \
        exp/utf8string.gox
@@ -257,13 +258,11 @@ toolexeclibgohtml_DATA = \
 toolexeclibgoimagedir = $(toolexeclibgodir)/image
 
 toolexeclibgoimage_DATA = \
-       image/bmp.gox \
        image/color.gox \
        image/draw.gox \
        image/gif.gox \
        image/jpeg.gox \
-       image/png.gox \
-       image/tiff.gox
+       image/png.gox
 
 toolexeclibgoindexdir = $(toolexeclibgodir)/index
 
@@ -327,8 +326,7 @@ toolexeclibgoosdir = $(toolexeclibgodir)/os
 
 toolexeclibgoos_DATA = \
        os/exec.gox \
-       os/user.gox \
-       os/signal.gox
+       os/user.gox
 
 toolexeclibgopathdir = $(toolexeclibgodir)/path
 
@@ -949,7 +947,6 @@ go_crypto_cipher_files = \
        go/crypto/cipher/cipher.go \
        go/crypto/cipher/ctr.go \
        go/crypto/cipher/io.go \
-       go/crypto/cipher/ocfb.go \
        go/crypto/cipher/ofb.go
 go_crypto_des_files = \
        go/crypto/des/block.go \
@@ -1107,6 +1104,8 @@ go_exp_proxy_files = \
        go/exp/proxy/per_host.go \
        go/exp/proxy/proxy.go \
        go/exp/proxy/socks5.go
+go_exp_signal_files = \
+       go/exp/signal/signal.go
 go_exp_terminal_files = \
        go/exp/terminal/terminal.go \
        go/exp/terminal/util.go
@@ -1179,9 +1178,6 @@ go_html_template_files = \
        go/html/template/transition.go \
        go/html/template/url.go
 
-go_image_bmp_files = \
-       go/image/bmp/reader.go
-
 go_image_color_files = \
        go/image/color/color.go \
        go/image/color/ycbcr.go
@@ -1203,12 +1199,6 @@ go_image_png_files = \
        go/image/png/reader.go \
        go/image/png/writer.go
 
-go_image_tiff_files = \
-       go/image/tiff/buffer.go \
-       go/image/tiff/compress.go \
-       go/image/tiff/consts.go \
-       go/image/tiff/reader.go
-
 go_index_suffixarray_files = \
        go/index/suffixarray/qsufsort.go \
        go/index/suffixarray/suffixarray.go
@@ -1317,9 +1307,6 @@ go_os_user_files = \
        go/os/user/user.go \
        go/os/user/lookup_unix.go
 
-go_os_signal_files = \
-       go/os/signal/signal.go
-
 go_path_filepath_files = \
        go/path/filepath/match.go \
        go/path/filepath/path.go \
@@ -1673,6 +1660,7 @@ libgo_go_objs = \
        exp/html.lo \
        exp/norm.lo \
        exp/proxy.lo \
+       exp/signal.lo \
        exp/terminal.lo \
        exp/types.lo \
        exp/utf8string.lo \
@@ -1693,13 +1681,11 @@ libgo_go_objs = \
        net/http/httptest.lo \
        net/http/httputil.lo \
        net/http/pprof.lo \
-       image/bmp.lo \
        image/color.lo \
        image/draw.lo \
        image/gif.lo \
        image/jpeg.lo \
        image/png.lo \
-       image/tiff.lo \
        index/suffixarray.lo \
        io/ioutil.lo \
        log/syslog.lo \
@@ -1720,7 +1706,6 @@ libgo_go_objs = \
        old/template.lo \
        $(os_lib_inotify_lo) \
        os/user.lo \
-       os/signal.lo \
        path/filepath.lo \
        regexp/syntax.lo \
        net/rpc/jsonrpc.lo \
@@ -2607,6 +2592,16 @@ exp/proxy/check: $(CHECK_DEPS)
        @$(CHECK)
 .PHONY: exp/proxy/check
 
+@go_include@ exp/signal.lo.dep
+exp/signal.lo.dep: $(go_exp_signal_files)
+       $(BUILDDEPS)
+exp/signal.lo: $(go_exp_signal_files)
+       $(BUILDPACKAGE)
+exp/signal/check: $(CHECK_DEPS)
+       @$(MKDIR_P) exp/signal
+       @$(CHECK)
+.PHONY: exp/signal/check
+
 @go_include@ exp/terminal.lo.dep
 exp/terminal.lo.dep: $(go_exp_terminal_files)
        $(BUILDDEPS)
@@ -2776,16 +2771,6 @@ hash/fnv/check: $(CHECK_DEPS)
        @$(CHECK)
 .PHONY: hash/fnv/check
 
-@go_include@ image/bmp.lo.dep
-image/bmp.lo.dep: $(go_image_bmp_files)
-       $(BUILDDEPS)
-image/bmp.lo: $(go_image_bmp_files)
-       $(BUILDPACKAGE)
-image/bmp/check: $(CHECK_DEPS)
-       @$(MKDIR_P) image/bmp
-       @$(CHECK)
-.PHONY: image/bmp/check
-
 @go_include@ image/color.lo.dep
 image/color.lo.dep: $(go_image_color_files)
        $(BUILDDEPS)
@@ -2836,16 +2821,6 @@ image/png/check: $(CHECK_DEPS)
        @$(CHECK)
 .PHONY: image/png/check
 
-@go_include@ image/tiff.lo.dep
-image/tiff.lo.dep: $(go_image_tiff_files)
-       $(BUILDDEPS)
-image/tiff.lo: $(go_image_tiff_files)
-       $(BUILDPACKAGE)
-image/tiff/check: $(CHECK_DEPS)
-       @$(MKDIR_P) image/tiff
-       @$(CHECK)
-.PHONY: image/tiff/check
-
 @go_include@ index/suffixarray.lo.dep
 index/suffixarray.lo.dep: $(go_index_suffixarray_files)
        $(BUILDDEPS)
@@ -3088,16 +3063,6 @@ os/user/check: $(CHECK_DEPS)
        @$(CHECK)
 .PHONY: os/user/check
 
-@go_include@ os/signal.lo.dep
-os/signal.lo.dep: $(go_os_signal_files)
-       $(BUILDDEPS)
-os/signal.lo: $(go_os_signal_files)
-       $(BUILDPACKAGE)
-os/signal/check: $(CHECK_DEPS)
-       @$(MKDIR_P) os/signal
-       @$(CHECK)
-.PHONY: os/signal/check
-
 @go_include@ path/filepath.lo.dep
 path/filepath.lo.dep: $(go_path_filepath_files)
        $(BUILDDEPS)
@@ -3412,6 +3377,8 @@ exp/norm.gox: exp/norm.lo
        $(BUILDGOX)
 exp/proxy.gox: exp/proxy.lo
        $(BUILDGOX)
+exp/signal.gox: exp/signal.lo
+       $(BUILDGOX)
 exp/terminal.gox: exp/terminal.lo
        $(BUILDGOX)
 exp/types.gox: exp/types.lo
@@ -3446,8 +3413,6 @@ hash/crc64.gox: hash/crc64.lo
 hash/fnv.gox: hash/fnv.lo
        $(BUILDGOX)
 
-image/bmp.gox: image/bmp.lo
-       $(BUILDGOX)
 image/color.gox: image/color.lo
        $(BUILDGOX)
 image/draw.gox: image/draw.lo
@@ -3458,8 +3423,6 @@ image/jpeg.gox: image/jpeg.lo
        $(BUILDGOX)
 image/png.gox: image/png.lo
        $(BUILDGOX)
-image/tiff.gox: image/tiff.lo
-       $(BUILDGOX)
 
 index/suffixarray.gox: index/suffixarray.lo
        $(BUILDGOX)
@@ -3518,8 +3481,6 @@ os/exec.gox: os/exec.lo
        $(BUILDGOX)
 os/user.gox: os/user.lo
        $(BUILDGOX)
-os/signal.gox: os/signal.lo
-       $(BUILDGOX)
 
 path/filepath.gox: path/filepath.lo
        $(BUILDGOX)
@@ -3637,6 +3598,7 @@ TEST_PACKAGES = \
        $(exp_inotify_check) \
        exp/norm/check \
        exp/proxy/check \
+       exp/signal/check \
        exp/terminal/check \
        exp/utf8string/check \
        html/template/check \
@@ -3656,7 +3618,6 @@ TEST_PACKAGES = \
        image/draw/check \
        image/jpeg/check \
        image/png/check \
-       image/tiff/check \
        index/suffixarray/check \
        io/ioutil/check \
        log/syslog/check \
@@ -3679,7 +3640,6 @@ TEST_PACKAGES = \
        old/template/check \
        os/exec/check \
        os/user/check \
-       os/signal/check \
        path/filepath/check \
        regexp/syntax/check \
        sync/atomic/check \
index d412e699f5ae86073dffdd8ce39c4a3bea944139..797cccac212457c363e2c37bf5793f2ad37c3b8e 100644 (file)
@@ -154,26 +154,26 @@ am__DEPENDENCIES_2 = bufio/bufio.lo bytes/bytes.lo bytes/index.lo \
        encoding/base32.lo encoding/base64.lo encoding/binary.lo \
        encoding/csv.lo encoding/gob.lo encoding/hex.lo \
        encoding/json.lo encoding/pem.lo encoding/xml.lo exp/ebnf.lo \
-       exp/html.lo exp/norm.lo exp/proxy.lo exp/terminal.lo \
-       exp/types.lo exp/utf8string.lo html/template.lo go/ast.lo \
-       go/build.lo go/doc.lo go/parser.lo go/printer.lo go/scanner.lo \
-       go/token.lo hash/adler32.lo hash/crc32.lo hash/crc64.lo \
-       hash/fnv.lo net/http/cgi.lo net/http/fcgi.lo \
-       net/http/httptest.lo net/http/httputil.lo net/http/pprof.lo \
-       image/bmp.lo image/color.lo image/draw.lo image/gif.lo \
-       image/jpeg.lo image/png.lo image/tiff.lo index/suffixarray.lo \
-       io/ioutil.lo log/syslog.lo log/syslog/syslog_c.lo math/big.lo \
-       math/cmplx.lo math/rand.lo mime/mime.lo mime/multipart.lo \
-       net/http.lo net/mail.lo net/rpc.lo net/smtp.lo \
-       net/textproto.lo net/url.lo old/netchan.lo old/regexp.lo \
-       old/template.lo $(am__DEPENDENCIES_1) os/user.lo os/signal.lo \
-       path/filepath.lo regexp/syntax.lo net/rpc/jsonrpc.lo \
-       runtime/debug.lo runtime/pprof.lo sync/atomic.lo \
-       sync/atomic_c.lo syscall/syscall.lo syscall/errno.lo \
-       syscall/wait.lo text/scanner.lo text/tabwriter.lo \
-       text/template.lo text/template/parse.lo testing/testing.lo \
-       testing/iotest.lo testing/quick.lo testing/script.lo \
-       unicode/utf16.lo unicode/utf8.lo
+       exp/html.lo exp/norm.lo exp/proxy.lo exp/signal.lo \
+       exp/terminal.lo exp/types.lo exp/utf8string.lo \
+       html/template.lo go/ast.lo go/build.lo go/doc.lo go/parser.lo \
+       go/printer.lo go/scanner.lo go/token.lo hash/adler32.lo \
+       hash/crc32.lo hash/crc64.lo hash/fnv.lo net/http/cgi.lo \
+       net/http/fcgi.lo net/http/httptest.lo net/http/httputil.lo \
+       net/http/pprof.lo image/color.lo image/draw.lo image/gif.lo \
+       image/jpeg.lo image/png.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/http.lo \
+       net/mail.lo net/rpc.lo net/smtp.lo net/textproto.lo net/url.lo \
+       old/netchan.lo old/regexp.lo old/template.lo \
+       $(am__DEPENDENCIES_1) os/user.lo path/filepath.lo \
+       regexp/syntax.lo net/rpc/jsonrpc.lo runtime/debug.lo \
+       runtime/pprof.lo sync/atomic.lo sync/atomic_c.lo \
+       syscall/syscall.lo syscall/errno.lo syscall/wait.lo \
+       text/scanner.lo text/tabwriter.lo text/template.lo \
+       text/template/parse.lo testing/testing.lo testing/iotest.lo \
+       testing/quick.lo testing/script.lo unicode/utf16.lo \
+       unicode/utf8.lo
 libgo_la_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \
        $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
        $(am__DEPENDENCIES_1)
@@ -679,6 +679,7 @@ toolexeclibgoexp_DATA = \
        $(exp_inotify_gox) \
        exp/norm.gox \
        exp/proxy.gox \
+       exp/signal.gox \
        exp/terminal.gox \
        exp/types.gox \
        exp/utf8string.gox
@@ -706,13 +707,11 @@ toolexeclibgohtml_DATA = \
 
 toolexeclibgoimagedir = $(toolexeclibgodir)/image
 toolexeclibgoimage_DATA = \
-       image/bmp.gox \
        image/color.gox \
        image/draw.gox \
        image/gif.gox \
        image/jpeg.gox \
-       image/png.gox \
-       image/tiff.gox
+       image/png.gox
 
 toolexeclibgoindexdir = $(toolexeclibgodir)/index
 toolexeclibgoindex_DATA = \
@@ -766,8 +765,7 @@ toolexeclibgoold_DATA = \
 toolexeclibgoosdir = $(toolexeclibgodir)/os
 toolexeclibgoos_DATA = \
        os/exec.gox \
-       os/user.gox \
-       os/signal.gox
+       os/user.gox
 
 toolexeclibgopathdir = $(toolexeclibgodir)/path
 toolexeclibgopath_DATA = \
@@ -1253,7 +1251,6 @@ go_crypto_cipher_files = \
        go/crypto/cipher/cipher.go \
        go/crypto/cipher/ctr.go \
        go/crypto/cipher/io.go \
-       go/crypto/cipher/ocfb.go \
        go/crypto/cipher/ofb.go
 
 go_crypto_des_files = \
@@ -1445,6 +1442,9 @@ go_exp_proxy_files = \
        go/exp/proxy/proxy.go \
        go/exp/proxy/socks5.go
 
+go_exp_signal_files = \
+       go/exp/signal/signal.go
+
 go_exp_terminal_files = \
        go/exp/terminal/terminal.go \
        go/exp/terminal/util.go
@@ -1528,9 +1528,6 @@ go_html_template_files = \
        go/html/template/transition.go \
        go/html/template/url.go
 
-go_image_bmp_files = \
-       go/image/bmp/reader.go
-
 go_image_color_files = \
        go/image/color/color.go \
        go/image/color/ycbcr.go
@@ -1552,12 +1549,6 @@ go_image_png_files = \
        go/image/png/reader.go \
        go/image/png/writer.go
 
-go_image_tiff_files = \
-       go/image/tiff/buffer.go \
-       go/image/tiff/compress.go \
-       go/image/tiff/consts.go \
-       go/image/tiff/reader.go
-
 go_index_suffixarray_files = \
        go/index/suffixarray/qsufsort.go \
        go/index/suffixarray/suffixarray.go
@@ -1677,9 +1668,6 @@ go_os_user_files = \
        go/os/user/user.go \
        go/os/user/lookup_unix.go
 
-go_os_signal_files = \
-       go/os/signal/signal.go
-
 go_path_filepath_files = \
        go/path/filepath/match.go \
        go/path/filepath/path.go \
@@ -1924,6 +1912,7 @@ libgo_go_objs = \
        exp/html.lo \
        exp/norm.lo \
        exp/proxy.lo \
+       exp/signal.lo \
        exp/terminal.lo \
        exp/types.lo \
        exp/utf8string.lo \
@@ -1944,13 +1933,11 @@ libgo_go_objs = \
        net/http/httptest.lo \
        net/http/httputil.lo \
        net/http/pprof.lo \
-       image/bmp.lo \
        image/color.lo \
        image/draw.lo \
        image/gif.lo \
        image/jpeg.lo \
        image/png.lo \
-       image/tiff.lo \
        index/suffixarray.lo \
        io/ioutil.lo \
        log/syslog.lo \
@@ -1971,7 +1958,6 @@ libgo_go_objs = \
        old/template.lo \
        $(os_lib_inotify_lo) \
        os/user.lo \
-       os/signal.lo \
        path/filepath.lo \
        regexp/syntax.lo \
        net/rpc/jsonrpc.lo \
@@ -2175,6 +2161,7 @@ TEST_PACKAGES = \
        $(exp_inotify_check) \
        exp/norm/check \
        exp/proxy/check \
+       exp/signal/check \
        exp/terminal/check \
        exp/utf8string/check \
        html/template/check \
@@ -2194,7 +2181,6 @@ TEST_PACKAGES = \
        image/draw/check \
        image/jpeg/check \
        image/png/check \
-       image/tiff/check \
        index/suffixarray/check \
        io/ioutil/check \
        log/syslog/check \
@@ -2217,7 +2203,6 @@ TEST_PACKAGES = \
        old/template/check \
        os/exec/check \
        os/user/check \
-       os/signal/check \
        path/filepath/check \
        regexp/syntax/check \
        sync/atomic/check \
@@ -5171,6 +5156,16 @@ exp/proxy/check: $(CHECK_DEPS)
        @$(CHECK)
 .PHONY: exp/proxy/check
 
+@go_include@ exp/signal.lo.dep
+exp/signal.lo.dep: $(go_exp_signal_files)
+       $(BUILDDEPS)
+exp/signal.lo: $(go_exp_signal_files)
+       $(BUILDPACKAGE)
+exp/signal/check: $(CHECK_DEPS)
+       @$(MKDIR_P) exp/signal
+       @$(CHECK)
+.PHONY: exp/signal/check
+
 @go_include@ exp/terminal.lo.dep
 exp/terminal.lo.dep: $(go_exp_terminal_files)
        $(BUILDDEPS)
@@ -5340,16 +5335,6 @@ hash/fnv/check: $(CHECK_DEPS)
        @$(CHECK)
 .PHONY: hash/fnv/check
 
-@go_include@ image/bmp.lo.dep
-image/bmp.lo.dep: $(go_image_bmp_files)
-       $(BUILDDEPS)
-image/bmp.lo: $(go_image_bmp_files)
-       $(BUILDPACKAGE)
-image/bmp/check: $(CHECK_DEPS)
-       @$(MKDIR_P) image/bmp
-       @$(CHECK)
-.PHONY: image/bmp/check
-
 @go_include@ image/color.lo.dep
 image/color.lo.dep: $(go_image_color_files)
        $(BUILDDEPS)
@@ -5400,16 +5385,6 @@ image/png/check: $(CHECK_DEPS)
        @$(CHECK)
 .PHONY: image/png/check
 
-@go_include@ image/tiff.lo.dep
-image/tiff.lo.dep: $(go_image_tiff_files)
-       $(BUILDDEPS)
-image/tiff.lo: $(go_image_tiff_files)
-       $(BUILDPACKAGE)
-image/tiff/check: $(CHECK_DEPS)
-       @$(MKDIR_P) image/tiff
-       @$(CHECK)
-.PHONY: image/tiff/check
-
 @go_include@ index/suffixarray.lo.dep
 index/suffixarray.lo.dep: $(go_index_suffixarray_files)
        $(BUILDDEPS)
@@ -5652,16 +5627,6 @@ os/user/check: $(CHECK_DEPS)
        @$(CHECK)
 .PHONY: os/user/check
 
-@go_include@ os/signal.lo.dep
-os/signal.lo.dep: $(go_os_signal_files)
-       $(BUILDDEPS)
-os/signal.lo: $(go_os_signal_files)
-       $(BUILDPACKAGE)
-os/signal/check: $(CHECK_DEPS)
-       @$(MKDIR_P) os/signal
-       @$(CHECK)
-.PHONY: os/signal/check
-
 @go_include@ path/filepath.lo.dep
 path/filepath.lo.dep: $(go_path_filepath_files)
        $(BUILDDEPS)
@@ -5971,6 +5936,8 @@ exp/norm.gox: exp/norm.lo
        $(BUILDGOX)
 exp/proxy.gox: exp/proxy.lo
        $(BUILDGOX)
+exp/signal.gox: exp/signal.lo
+       $(BUILDGOX)
 exp/terminal.gox: exp/terminal.lo
        $(BUILDGOX)
 exp/types.gox: exp/types.lo
@@ -6005,8 +5972,6 @@ hash/crc64.gox: hash/crc64.lo
 hash/fnv.gox: hash/fnv.lo
        $(BUILDGOX)
 
-image/bmp.gox: image/bmp.lo
-       $(BUILDGOX)
 image/color.gox: image/color.lo
        $(BUILDGOX)
 image/draw.gox: image/draw.lo
@@ -6017,8 +5982,6 @@ image/jpeg.gox: image/jpeg.lo
        $(BUILDGOX)
 image/png.gox: image/png.lo
        $(BUILDGOX)
-image/tiff.gox: image/tiff.lo
-       $(BUILDGOX)
 
 index/suffixarray.gox: index/suffixarray.lo
        $(BUILDGOX)
@@ -6077,8 +6040,6 @@ os/exec.gox: os/exec.lo
        $(BUILDGOX)
 os/user.gox: os/user.lo
        $(BUILDGOX)
-os/signal.gox: os/signal.lo
-       $(BUILDGOX)
 
 path/filepath.gox: path/filepath.lo
        $(BUILDGOX)
index 4dd0f4f434421a8d8b1f473ffa1086e4a0f1c0c0..c3009869b60a0d17d12fe49f27246c4a7625e7b1 100644 (file)
@@ -117,7 +117,7 @@ func (rc *ReadCloser) Close() error {
 }
 
 // Open returns a ReadCloser that provides access to the File's contents.
-// It is safe to Open and Read from files concurrently.
+// Multiple files may be read concurrently.
 func (f *File) Open() (rc io.ReadCloser, err error) {
        bodyOffset, err := f.findBodyOffset()
        if err != nil {
index 9407e35d5c08ce4a7bbacfad0e3ec7ed2bde02c9..935860e791efdd44b4229b6208e6d999afcf8b61 100644 (file)
@@ -69,8 +69,23 @@ var tests = []ZipTest{
                        },
                },
        },
-       {Name: "readme.zip"},
-       {Name: "readme.notzip", Error: ErrFormat},
+       {
+               Name: "symlink.zip",
+               File: []ZipTestFile{
+                       {
+                               Name:    "symlink",
+                               Content: []byte("../target"),
+                               Mode:    0777 | os.ModeSymlink,
+                       },
+               },
+       },
+       {
+               Name: "readme.zip",
+       },
+       {
+               Name:  "readme.notzip",
+               Error: ErrFormat,
+       },
        {
                Name: "dd.zip",
                File: []ZipTestFile{
index 67e9658629419a06bdbf064254735012fdd71372..35dcec6468b2aff7b2dd664adb8b4abb1074d314 100644 (file)
@@ -57,8 +57,8 @@ type FileHeader struct {
 }
 
 // FileInfo returns an os.FileInfo for the FileHeader.
-func (fh *FileHeader) FileInfo() os.FileInfo {
-       return headerFileInfo{fh}
+func (h *FileHeader) FileInfo() os.FileInfo {
+       return headerFileInfo{h}
 }
 
 // headerFileInfo implements os.FileInfo.
@@ -71,6 +71,7 @@ func (fi headerFileInfo) Size() int64        { return int64(fi.fh.UncompressedSi
 func (fi headerFileInfo) IsDir() bool        { return fi.Mode().IsDir() }
 func (fi headerFileInfo) ModTime() time.Time { return fi.fh.ModTime() }
 func (fi headerFileInfo) Mode() os.FileMode  { return fi.fh.Mode() }
+func (fi headerFileInfo) Sys() interface{}   { return fi.fh }
 
 // FileInfoHeader creates a partially-populated FileHeader from an
 // os.FileInfo.
@@ -151,13 +152,20 @@ func (h *FileHeader) SetModTime(t time.Time) {
        h.ModifiedDate, h.ModifiedTime = timeToMsDosTime(t)
 }
 
-// traditional names for Unix constants
 const (
-       s_IFMT  = 0xf000
-       s_IFDIR = 0x4000
-       s_IFREG = 0x8000
-       s_ISUID = 0x800
-       s_ISGID = 0x400
+       // Unix constants. The specification doesn't mention them,
+       // but these seem to be the values agreed on by tools.
+       s_IFMT   = 0xf000
+       s_IFSOCK = 0xc000
+       s_IFLNK  = 0xa000
+       s_IFREG  = 0x8000
+       s_IFBLK  = 0x6000
+       s_IFDIR  = 0x4000
+       s_IFCHR  = 0x2000
+       s_IFIFO  = 0x1000
+       s_ISUID  = 0x800
+       s_ISGID  = 0x400
+       s_ISVTX  = 0x200
 
        msdosDir      = 0x10
        msdosReadOnly = 0x01
@@ -205,10 +213,23 @@ func msdosModeToFileMode(m uint32) (mode os.FileMode) {
 
 func fileModeToUnixMode(mode os.FileMode) uint32 {
        var m uint32
-       if mode&os.ModeDir != 0 {
-               m = s_IFDIR
-       } else {
+       switch mode & os.ModeType {
+       default:
                m = s_IFREG
+       case os.ModeDir:
+               m = s_IFDIR
+       case os.ModeSymlink:
+               m = s_IFLNK
+       case os.ModeNamedPipe:
+               m = s_IFIFO
+       case os.ModeSocket:
+               m = s_IFSOCK
+       case os.ModeDevice:
+               if mode&os.ModeCharDevice != 0 {
+                       m = s_IFCHR
+               } else {
+                       m = s_IFBLK
+               }
        }
        if mode&os.ModeSetuid != 0 {
                m |= s_ISUID
@@ -216,13 +237,29 @@ func fileModeToUnixMode(mode os.FileMode) uint32 {
        if mode&os.ModeSetgid != 0 {
                m |= s_ISGID
        }
+       if mode&os.ModeSticky != 0 {
+               m |= s_ISVTX
+       }
        return m | uint32(mode&0777)
 }
 
 func unixModeToFileMode(m uint32) os.FileMode {
-       var mode os.FileMode
-       if m&s_IFMT == s_IFDIR {
+       mode := os.FileMode(m & 0777)
+       switch m & s_IFMT {
+       case s_IFBLK:
+               mode |= os.ModeDevice
+       case s_IFCHR:
+               mode |= os.ModeDevice | os.ModeCharDevice
+       case s_IFDIR:
                mode |= os.ModeDir
+       case s_IFIFO:
+               mode |= os.ModeNamedPipe
+       case s_IFLNK:
+               mode |= os.ModeSymlink
+       case s_IFREG:
+               // nothing to do
+       case s_IFSOCK:
+               mode |= os.ModeSocket
        }
        if m&s_ISGID != 0 {
                mode |= os.ModeSetgid
@@ -230,5 +267,8 @@ func unixModeToFileMode(m uint32) os.FileMode {
        if m&s_ISUID != 0 {
                mode |= os.ModeSetuid
        }
-       return mode | os.FileMode(m&0777)
+       if m&s_ISVTX != 0 {
+               mode |= os.ModeSticky
+       }
+       return mode
 }
diff --git a/libgo/go/archive/zip/testdata/symlink.zip b/libgo/go/archive/zip/testdata/symlink.zip
new file mode 100644 (file)
index 0000000..af84693
Binary files /dev/null and b/libgo/go/archive/zip/testdata/symlink.zip differ
index b1b128e2a7da406c7ef11d91e5ba9734a71b2859..a4f0654474a6711f097da434fdd3e3abfcd8e330 100644 (file)
@@ -19,7 +19,7 @@ import (
 
 // Writer implements a zip file writer.
 type Writer struct {
-       *countWriter
+       countWriter
        dir    []*header
        last   *fileWriter
        closed bool
@@ -32,7 +32,7 @@ type header struct {
 
 // NewWriter returns a new Writer writing a zip file to w.
 func NewWriter(w io.Writer) *Writer {
-       return &Writer{countWriter: &countWriter{w: bufio.NewWriter(w)}}
+       return &Writer{countWriter: countWriter{w: bufio.NewWriter(w)}}
 }
 
 // Close finishes writing the zip file by writing the central directory.
index 5a576b1c32c3abd36cbb9569db1ee7c16d4b3d4a..ce93fae19e53da3508c67166945b2133c5aaa72d 100644 (file)
@@ -47,10 +47,10 @@ var writeTests = []WriteTest{
                Mode:   0755 | os.ModeSetgid,
        },
        {
-               Name:   "setgid",
-               Data:   []byte("setgid file"),
+               Name:   "symlink",
+               Data:   []byte("../link/target"),
                Method: Deflate,
-               Mode:   0755 | os.ModeSetgid,
+               Mode:   0755 | os.ModeSymlink,
        },
 }
 
index acd3d938218eddb9399408320a7e6a694d9e9e4a..1a260cc569fa56572d8a5d25a4a67353fa597b31 100644 (file)
@@ -85,4 +85,7 @@ func TestFileHeaderRoundTrip(t *testing.T) {
        if !reflect.DeepEqual(fh, fh2) {
                t.Errorf("mismatch\n input=%#v\noutput=%#v\nerr=%v", fh, fh2, err)
        }
+       if sysfh, ok := fi.Sys().(*FileHeader); !ok && sysfh != fh {
+               t.Errorf("Sys didn't return original *FileHeader")
+       }
 }
index 907a9dcb719aeddfa130c5fa74ec444049da7748..156dddfcf071f37d527b929ad33a202a44e4de3f 100644 (file)
@@ -9,8 +9,8 @@ package bufio
 
 import (
        "bytes"
+       "errors"
        "io"
-       "strconv"
        "unicode/utf8"
 )
 
@@ -18,28 +18,14 @@ const (
        defaultBufSize = 4096
 )
 
-// Errors introduced by this package.
-type Error struct {
-       ErrorString string
-}
-
-func (err *Error) Error() string { return err.ErrorString }
-
 var (
-       ErrInvalidUnreadByte error = &Error{"bufio: invalid use of UnreadByte"}
-       ErrInvalidUnreadRune error = &Error{"bufio: invalid use of UnreadRune"}
-       ErrBufferFull        error = &Error{"bufio: buffer full"}
-       ErrNegativeCount     error = &Error{"bufio: negative count"}
-       errInternal          error = &Error{"bufio: internal error"}
+       ErrInvalidUnreadByte = errors.New("bufio: invalid use of UnreadByte")
+       ErrInvalidUnreadRune = errors.New("bufio: invalid use of UnreadRune")
+       ErrBufferFull        = errors.New("bufio: buffer full")
+       ErrNegativeCount     = errors.New("bufio: negative count")
+       errInternal          = errors.New("bufio: internal error")
 )
 
-// BufSizeError is the error representing an invalid buffer size.
-type BufSizeError int
-
-func (b BufSizeError) Error() string {
-       return "bufio: bad buffer size " + strconv.Itoa(int(b))
-}
-
 // Buffered input.
 
 // Reader implements buffering for an io.Reader object.
@@ -54,35 +40,29 @@ type Reader struct {
 
 const minReadBufferSize = 16
 
-// NewReaderSize creates a new Reader whose buffer has the specified size,
-// which must be at least 16 bytes.  If the argument io.Reader is already a
-// Reader with large enough size, it returns the underlying Reader.
-// It returns the Reader and any error.
-func NewReaderSize(rd io.Reader, size int) (*Reader, error) {
-       if size < minReadBufferSize {
-               return nil, BufSizeError(size)
-       }
+// NewReaderSize returns a new Reader whose buffer has at least the specified
+// size. If the argument io.Reader is already a Reader with large enough
+// size, it returns the underlying Reader.
+func NewReaderSize(rd io.Reader, size int) *Reader {
        // Is it already a Reader?
        b, ok := rd.(*Reader)
        if ok && len(b.buf) >= size {
-               return b, nil
+               return b
+       }
+       if size < minReadBufferSize {
+               size = minReadBufferSize
+       }
+       return &Reader{
+               buf:          make([]byte, size),
+               rd:           rd,
+               lastByte:     -1,
+               lastRuneSize: -1,
        }
-       b = new(Reader)
-       b.buf = make([]byte, size)
-       b.rd = rd
-       b.lastByte = -1
-       b.lastRuneSize = -1
-       return b, nil
 }
 
 // NewReader returns a new Reader whose buffer has the default size.
 func NewReader(rd io.Reader) *Reader {
-       b, err := NewReaderSize(rd, defaultBufSize)
-       if err != nil {
-               // cannot happen - defaultBufSize is a valid size
-               panic(err)
-       }
-       return b
+       return NewReaderSize(rd, defaultBufSize)
 }
 
 // fill reads a new chunk into the buffer.
@@ -208,7 +188,8 @@ func (b *Reader) UnreadByte() error {
 }
 
 // ReadRune reads a single UTF-8 encoded Unicode character and returns the
-// rune and its size in bytes.
+// rune and its size in bytes. If the encoded rune is invalid, it consumes one byte
+// and returns unicode.ReplacementChar (U+FFFD) with a size of 1.
 func (b *Reader) ReadRune() (r rune, size int, err error) {
        for b.r+utf8.UTFMax > b.w && !utf8.FullRune(b.buf[b.r:b.w]) && b.err == nil {
                b.fill()
@@ -392,6 +373,8 @@ func (b *Reader) ReadString(delim byte) (line string, err error) {
 // buffered output
 
 // Writer implements buffering for an io.Writer object.
+// If an error occurs writing to a Writer, no more data will be
+// accepted and all subsequent writes will return the error.
 type Writer struct {
        err error
        buf []byte
@@ -399,33 +382,27 @@ type Writer struct {
        wr  io.Writer
 }
 
-// NewWriterSize creates a new Writer whose buffer has the specified size,
-// which must be greater than zero. If the argument io.Writer is already a
-// Writer with large enough size, it returns the underlying Writer.
-// It returns the Writer and any error.
-func NewWriterSize(wr io.Writer, size int) (*Writer, error) {
-       if size <= 0 {
-               return nil, BufSizeError(size)
-       }
+// NewWriterSize returns a new Writer whose buffer has at least the specified
+// size. If the argument io.Writer is already a Writer with large enough
+// size, it returns the underlying Writer.
+func NewWriterSize(wr io.Writer, size int) *Writer {
        // Is it already a Writer?
        b, ok := wr.(*Writer)
        if ok && len(b.buf) >= size {
-               return b, nil
+               return b
+       }
+       if size <= 0 {
+               size = defaultBufSize
        }
        b = new(Writer)
        b.buf = make([]byte, size)
        b.wr = wr
-       return b, nil
+       return b
 }
 
 // NewWriter returns a new Writer whose buffer has the default size.
 func NewWriter(wr io.Writer) *Writer {
-       b, err := NewWriterSize(wr, defaultBufSize)
-       if err != nil {
-               // cannot happen - defaultBufSize is valid size
-               panic(err)
-       }
-       return b
+       return NewWriterSize(wr, defaultBufSize)
 }
 
 // Flush writes any buffered data to the underlying io.Writer.
index 6463bbb9cb3fde048fae35db8fffcb64bf7b31c8..9aec61ec426c9a65715f5d7f3943b355be686fd9 100644 (file)
@@ -161,7 +161,7 @@ func TestReader(t *testing.T) {
                                        bufreader := bufreaders[j]
                                        bufsize := bufsizes[k]
                                        read := readmaker.fn(bytes.NewBufferString(text))
-                                       buf, _ := NewReaderSize(read, bufsize)
+                                       buf := NewReaderSize(read, bufsize)
                                        s := bufreader.fn(buf)
                                        if s != text {
                                                t.Errorf("reader=%s fn=%s bufsize=%d want=%q got=%q",
@@ -379,18 +379,14 @@ func TestWriter(t *testing.T) {
                        // and that the data is correct.
 
                        w.Reset()
-                       buf, e := NewWriterSize(w, bs)
+                       buf := NewWriterSize(w, bs)
                        context := fmt.Sprintf("nwrite=%d bufsize=%d", nwrite, bs)
-                       if e != nil {
-                               t.Errorf("%s: NewWriterSize %d: %v", context, bs, e)
-                               continue
-                       }
                        n, e1 := buf.Write(data[0:nwrite])
                        if e1 != nil || n != nwrite {
                                t.Errorf("%s: buf.Write %d = %d, %v", context, nwrite, n, e1)
                                continue
                        }
-                       if e = buf.Flush(); e != nil {
+                       if e := buf.Flush(); e != nil {
                                t.Errorf("%s: buf.Flush = %v", context, e)
                        }
 
@@ -447,23 +443,14 @@ func TestWriteErrors(t *testing.T) {
 
 func TestNewReaderSizeIdempotent(t *testing.T) {
        const BufSize = 1000
-       b, err := NewReaderSize(bytes.NewBufferString("hello world"), BufSize)
-       if err != nil {
-               t.Error("NewReaderSize create fail", err)
-       }
+       b := NewReaderSize(bytes.NewBufferString("hello world"), BufSize)
        // Does it recognize itself?
-       b1, err2 := NewReaderSize(b, BufSize)
-       if err2 != nil {
-               t.Error("NewReaderSize #2 create fail", err2)
-       }
+       b1 := NewReaderSize(b, BufSize)
        if b1 != b {
                t.Error("NewReaderSize did not detect underlying Reader")
        }
        // Does it wrap if existing buffer is too small?
-       b2, err3 := NewReaderSize(b, 2*BufSize)
-       if err3 != nil {
-               t.Error("NewReaderSize #3 create fail", err3)
-       }
+       b2 := NewReaderSize(b, 2*BufSize)
        if b2 == b {
                t.Error("NewReaderSize did not enlarge buffer")
        }
@@ -471,23 +458,14 @@ func TestNewReaderSizeIdempotent(t *testing.T) {
 
 func TestNewWriterSizeIdempotent(t *testing.T) {
        const BufSize = 1000
-       b, err := NewWriterSize(new(bytes.Buffer), BufSize)
-       if err != nil {
-               t.Error("NewWriterSize create fail", err)
-       }
+       b := NewWriterSize(new(bytes.Buffer), BufSize)
        // Does it recognize itself?
-       b1, err2 := NewWriterSize(b, BufSize)
-       if err2 != nil {
-               t.Error("NewWriterSize #2 create fail", err2)
-       }
+       b1 := NewWriterSize(b, BufSize)
        if b1 != b {
                t.Error("NewWriterSize did not detect underlying Writer")
        }
        // Does it wrap if existing buffer is too small?
-       b2, err3 := NewWriterSize(b, 2*BufSize)
-       if err3 != nil {
-               t.Error("NewWriterSize #3 create fail", err3)
-       }
+       b2 := NewWriterSize(b, 2*BufSize)
        if b2 == b {
                t.Error("NewWriterSize did not enlarge buffer")
        }
@@ -496,10 +474,7 @@ func TestNewWriterSizeIdempotent(t *testing.T) {
 func TestWriteString(t *testing.T) {
        const BufSize = 8
        buf := new(bytes.Buffer)
-       b, err := NewWriterSize(buf, BufSize)
-       if err != nil {
-               t.Error("NewWriterSize create fail", err)
-       }
+       b := NewWriterSize(buf, BufSize)
        b.WriteString("0")                         // easy
        b.WriteString("123456")                    // still easy
        b.WriteString("7890")                      // easy after flush
@@ -516,10 +491,7 @@ func TestWriteString(t *testing.T) {
 
 func TestBufferFull(t *testing.T) {
        const longString = "And now, hello, world! It is the time for all good men to come to the aid of their party"
-       buf, err := NewReaderSize(strings.NewReader(longString), minReadBufferSize)
-       if err != nil {
-               t.Fatal("NewReaderSize:", err)
-       }
+       buf := NewReaderSize(strings.NewReader(longString), minReadBufferSize)
        line, err := buf.ReadSlice('!')
        if string(line) != "And now, hello, " || err != ErrBufferFull {
                t.Errorf("first ReadSlice(,) = %q, %v", line, err)
@@ -533,7 +505,7 @@ func TestBufferFull(t *testing.T) {
 func TestPeek(t *testing.T) {
        p := make([]byte, 10)
        // string is 16 (minReadBufferSize) long.
-       buf, _ := NewReaderSize(strings.NewReader("abcdefghijklmnop"), minReadBufferSize)
+       buf := NewReaderSize(strings.NewReader("abcdefghijklmnop"), minReadBufferSize)
        if s, err := buf.Peek(1); string(s) != "a" || err != nil {
                t.Fatalf("want %q got %q, err=%v", "a", string(s), err)
        }
@@ -609,7 +581,7 @@ func testReadLine(t *testing.T, input []byte) {
        for stride := 1; stride < 2; stride++ {
                done := 0
                reader := testReader{input, stride}
-               l, _ := NewReaderSize(&reader, len(input)+1)
+               l := NewReaderSize(&reader, len(input)+1)
                for {
                        line, isPrefix, err := l.ReadLine()
                        if len(line) > 0 && err != nil {
@@ -646,7 +618,7 @@ func TestLineTooLong(t *testing.T) {
                data = append(data, '0'+byte(i%10))
        }
        buf := bytes.NewBuffer(data)
-       l, _ := NewReaderSize(buf, minReadBufferSize)
+       l := NewReaderSize(buf, minReadBufferSize)
        line, isPrefix, err := l.ReadLine()
        if !isPrefix || !bytes.Equal(line, data[:minReadBufferSize]) || err != nil {
                t.Errorf("bad result for first line: got %q want %q %v", line, data[:minReadBufferSize], err)
@@ -673,7 +645,7 @@ func TestReadAfterLines(t *testing.T) {
        inbuf := bytes.NewBuffer([]byte(line1 + "\n" + restData))
        outbuf := new(bytes.Buffer)
        maxLineLength := len(line1) + len(restData)/2
-       l, _ := NewReaderSize(inbuf, maxLineLength)
+       l := NewReaderSize(inbuf, maxLineLength)
        line, isPrefix, err := l.ReadLine()
        if isPrefix || err != nil || string(line) != line1 {
                t.Errorf("bad result for first line: isPrefix=%v err=%v line=%q", isPrefix, err, string(line))
@@ -688,7 +660,7 @@ func TestReadAfterLines(t *testing.T) {
 }
 
 func TestReadEmptyBuffer(t *testing.T) {
-       l, _ := NewReaderSize(bytes.NewBuffer(nil), minReadBufferSize)
+       l := NewReaderSize(new(bytes.Buffer), minReadBufferSize)
        line, isPrefix, err := l.ReadLine()
        if err != io.EOF {
                t.Errorf("expected EOF from ReadLine, got '%s' %t %s", line, isPrefix, err)
@@ -696,7 +668,7 @@ func TestReadEmptyBuffer(t *testing.T) {
 }
 
 func TestLinesAfterRead(t *testing.T) {
-       l, _ := NewReaderSize(bytes.NewBuffer([]byte("foo")), minReadBufferSize)
+       l := NewReaderSize(bytes.NewBuffer([]byte("foo")), minReadBufferSize)
        _, err := ioutil.ReadAll(l)
        if err != nil {
                t.Error(err)
@@ -752,10 +724,7 @@ func TestReadLineNewlines(t *testing.T) {
 }
 
 func testReadLineNewlines(t *testing.T, input string, expect []readLineResult) {
-       b, err := NewReaderSize(strings.NewReader(input), minReadBufferSize)
-       if err != nil {
-               t.Fatal(err)
-       }
+       b := NewReaderSize(strings.NewReader(input), minReadBufferSize)
        for i, e := range expect {
                line, isPrefix, err := b.ReadLine()
                if bytes.Compare(line, e.line) != 0 {
index 2c3eb6a596bb8e57dc95d5bb15497a6882d66dce..a95c2afd005fe302b8b6e557481d11a2f8e6847d 100644 (file)
@@ -57,10 +57,13 @@ func (b *Buffer) String() string {
 func (b *Buffer) Len() int { return len(b.buf) - b.off }
 
 // Truncate discards all but the first n unread bytes from the buffer.
-// It is an error to call b.Truncate(n) with n > b.Len().
+// It panics if n is negative or greater than the length of the buffer.
 func (b *Buffer) Truncate(n int) {
        b.lastRead = opInvalid
-       if n == 0 {
+       switch {
+       case n < 0 || n > b.Len():
+               panic("bytes.Buffer: truncation out of range")
+       case n == 0:
                // Reuse buffer space.
                b.off = 0
        }
@@ -366,14 +369,15 @@ func (b *Buffer) ReadString(delim byte) (line string, err error) {
 // buf should have the desired capacity but a length of zero.
 //
 // In most cases, new(Buffer) (or just declaring a Buffer variable) is
-// preferable to NewBuffer.  In particular, passing a non-empty buf to
-// NewBuffer and then writing to the Buffer will overwrite buf, not append to
-// it.
+// sufficient to initialize a Buffer.
 func NewBuffer(buf []byte) *Buffer { return &Buffer{buf: buf} }
 
 // NewBufferString creates and initializes a new Buffer using string s as its
-// initial contents.  It is intended to prepare a buffer to read an existing
-// string.  See the warnings about NewBuffer; similar issues apply here.
+// initial contents. It is intended to prepare a buffer to read an existing
+// string.
+//
+// In most cases, new(Buffer) (or just declaring a Buffer variable) is
+// sufficient to initialize a Buffer.
 func NewBufferString(s string) *Buffer {
        return &Buffer{buf: []byte(s)}
 }
index 1e725890b731e555fbdfd8dce9733b16a771bc7e..8505da706c9aa5e01ee67871749b8940f3c3200f 100644 (file)
@@ -102,7 +102,7 @@ func (d *compressor) fillDeflate(b []byte) int {
                if d.blockStart >= windowSize {
                        d.blockStart -= windowSize
                } else {
-                       d.blockStart = skipNever
+                       d.blockStart = math.MaxInt32
                }
                d.hashOffset += windowSize
        }
index 24881d31c069ff7e5f9fd72c6ffee29e21f4597f..75d801df4053230e095b23825c76f770d02148a6 100644 (file)
@@ -229,14 +229,14 @@ func testToFromWithLevel(t *testing.T, level int, input []byte, name string) err
 }
 
 func testToFromWithLevelAndLimit(t *testing.T, level int, input []byte, name string, limit int) error {
-       buffer := bytes.NewBuffer(nil)
-       w := NewWriter(buffer, level)
+       var buffer bytes.Buffer
+       w := NewWriter(&buffer, level)
        w.Write(input)
        w.Close()
        if limit > 0 && buffer.Len() > limit {
                t.Errorf("level: %d, len(compress(data)) = %d > limit = %d", level, buffer.Len(), limit)
        }
-       r := NewReader(buffer)
+       r := NewReader(&buffer)
        out, err := ioutil.ReadAll(r)
        if err != nil {
                t.Errorf("read: %s", err)
index 4873b0fce36ed8be4f3a30c6f26c8d25d2c27125..009cce6267a1c9c26597174f03a79a14802345b7 100644 (file)
@@ -121,61 +121,6 @@ func (h *huffmanEncoder) bitLength(freq []int32) int64 {
        return total
 }
 
-// Generate elements in the chain using an iterative algorithm.
-func (h *huffmanEncoder) generateChains(top *levelInfo, list []literalNode) {
-       n := len(list)
-       list = list[0 : n+1]
-       list[n] = maxNode()
-
-       l := top
-       for {
-               if l.nextPairFreq == math.MaxInt32 && l.nextCharFreq == math.MaxInt32 {
-                       // We've run out of both leafs and pairs.
-                       // End all calculations for this level.
-                       // To m sure we never come back to this level or any lower level,
-                       // set nextPairFreq impossibly large.
-                       l.lastChain = nil
-                       l.needed = 0
-                       l = l.up
-                       l.nextPairFreq = math.MaxInt32
-                       continue
-               }
-
-               prevFreq := l.lastChain.freq
-               if l.nextCharFreq < l.nextPairFreq {
-                       // The next item on this row is a leaf node.
-                       n := l.lastChain.leafCount + 1
-                       l.lastChain = &chain{l.nextCharFreq, n, l.lastChain.up}
-                       l.nextCharFreq = list[n].freq
-               } else {
-                       // The next item on this row is a pair from the previous row.
-                       // nextPairFreq isn't valid until we generate two
-                       // more values in the level below
-                       l.lastChain = &chain{l.nextPairFreq, l.lastChain.leafCount, l.down.lastChain}
-                       l.down.needed = 2
-               }
-
-               if l.needed--; l.needed == 0 {
-                       // We've done everything we need to do for this level.
-                       // Continue calculating one level up.  Fill in nextPairFreq
-                       // of that level with the sum of the two nodes we've just calculated on
-                       // this level.
-                       up := l.up
-                       if up == nil {
-                               // All done!
-                               return
-                       }
-                       up.nextPairFreq = prevFreq + l.lastChain.freq
-                       l = up
-               } else {
-                       // If we stole from below, move down temporarily to replenish it.
-                       for l.down.needed > 0 {
-                               l = l.down
-                       }
-               }
-       }
-}
-
 // Return the number of literals assigned to each bit size in the Huffman encoding
 //
 // This method is only called when list.length >= 3
index 09821573cc03cb6db4ed9ccbfd54f6a4866f0fe6..e5be12f54e8d0cd65fecadbc603a6b76098e8ea0 100644 (file)
@@ -81,7 +81,7 @@ var lzwTests = []lzwTest{
 }
 
 func TestReader(t *testing.T) {
-       b := bytes.NewBuffer(nil)
+       var b bytes.Buffer
        for _, tt := range lzwTests {
                d := strings.Split(tt.desc, ";")
                var order Order
@@ -97,7 +97,7 @@ func TestReader(t *testing.T) {
                rc := NewReader(strings.NewReader(tt.compressed), order, litWidth)
                defer rc.Close()
                b.Reset()
-               n, err := io.Copy(b, rc)
+               n, err := io.Copy(&b, rc)
                if err != nil {
                        if err != tt.err {
                                t.Errorf("%s: io.Copy: %v want %v", tt.desc, err, tt.err)
@@ -116,7 +116,7 @@ func benchmarkDecoder(b *testing.B, n int) {
        b.SetBytes(int64(n))
        buf0, _ := ioutil.ReadFile("../testdata/e.txt")
        buf0 = buf0[:10000]
-       compressed := bytes.NewBuffer(nil)
+       compressed := new(bytes.Buffer)
        w := NewWriter(compressed, LSB, 8)
        for i := 0; i < n; i += len(buf0) {
                io.Copy(w, bytes.NewBuffer(buf0))
index a71894da3200ab92258727682f8344bd1a5f47fd..1c75d088ddf2879a172a6640354012999a38d408 100644 (file)
@@ -124,8 +124,8 @@ func TestWriterDict(t *testing.T) {
 
 func TestWriterDictIsUsed(t *testing.T) {
        var input = []byte("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.")
-       buf := bytes.NewBuffer(nil)
-       compressor, err := NewWriterDict(buf, BestCompression, input)
+       var buf bytes.Buffer
+       compressor, err := NewWriterDict(&buf, BestCompression, input)
        if err != nil {
                t.Errorf("error in NewWriterDict: %s", err)
                return
index 4632f882a4c12be0cdaa7cd2eb1d79c57d45eb2d..a48929cf5d56cb1538fc9460bfa1d63f1c00ecb2 100644 (file)
@@ -56,7 +56,7 @@ type cbcDecrypter cbc
 
 // NewCBCDecrypter returns a BlockMode which decrypts in cipher block chaining
 // mode, using the given Block. The length of iv must be the same as the
-// Block's block size as must match the iv used to encrypt the data.
+// Block's block size and must match the iv used to encrypt the data.
 func NewCBCDecrypter(b Block, iv []byte) BlockMode {
        return (*cbcDecrypter)(newCBC(b, iv))
 }
index 9888c9806f314c55addca100987ae32d55819f35..76048fbf33953684faa83e44103b3110f59add7c 100644 (file)
@@ -9,7 +9,7 @@ import "io"
 // The Stream* objects are so simple that all their members are public. Users
 // can create them themselves.
 
-// StreamReader wraps a Stream into an io.Reader. It simply calls XORKeyStream
+// StreamReader wraps a Stream into an io.Reader. It calls XORKeyStream
 // to process each slice of data which passes through.
 type StreamReader struct {
        S Stream
@@ -22,7 +22,7 @@ func (r StreamReader) Read(dst []byte) (n int, err error) {
        return
 }
 
-// StreamWriter wraps a Stream into an io.Writer. It simply calls XORKeyStream
+// StreamWriter wraps a Stream into an io.Writer. It calls XORKeyStream
 // to process each slice of data which passes through. If any Write call
 // returns short then the StreamWriter is out of sync and must be discarded.
 type StreamWriter struct {
diff --git a/libgo/go/crypto/cipher/ocfb.go b/libgo/go/crypto/cipher/ocfb.go
deleted file mode 100644 (file)
index 031e74a..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// OpenPGP CFB Mode. http://tools.ietf.org/html/rfc4880#section-13.9
-
-package cipher
-
-type ocfbEncrypter struct {
-       b       Block
-       fre     []byte
-       outUsed int
-}
-
-// An OCFBResyncOption determines if the "resynchronization step" of OCFB is
-// performed.
-type OCFBResyncOption bool
-
-const (
-       OCFBResync   OCFBResyncOption = true
-       OCFBNoResync OCFBResyncOption = false
-)
-
-// NewOCFBEncrypter returns a Stream which encrypts data with OpenPGP's cipher
-// feedback mode using the given Block, and an initial amount of ciphertext.
-// randData must be random bytes and be the same length as the Block's block
-// size. Resync determines if the "resynchronization step" from RFC 4880, 13.9
-// step 7 is performed. Different parts of OpenPGP vary on this point.
-func NewOCFBEncrypter(block Block, randData []byte, resync OCFBResyncOption) (Stream, []byte) {
-       blockSize := block.BlockSize()
-       if len(randData) != blockSize {
-               return nil, nil
-       }
-
-       x := &ocfbEncrypter{
-               b:       block,
-               fre:     make([]byte, blockSize),
-               outUsed: 0,
-       }
-       prefix := make([]byte, blockSize+2)
-
-       block.Encrypt(x.fre, x.fre)
-       for i := 0; i < blockSize; i++ {
-               prefix[i] = randData[i] ^ x.fre[i]
-       }
-
-       block.Encrypt(x.fre, prefix[:blockSize])
-       prefix[blockSize] = x.fre[0] ^ randData[blockSize-2]
-       prefix[blockSize+1] = x.fre[1] ^ randData[blockSize-1]
-
-       if resync {
-               block.Encrypt(x.fre, prefix[2:])
-       } else {
-               x.fre[0] = prefix[blockSize]
-               x.fre[1] = prefix[blockSize+1]
-               x.outUsed = 2
-       }
-       return x, prefix
-}
-
-func (x *ocfbEncrypter) XORKeyStream(dst, src []byte) {
-       for i := 0; i < len(src); i++ {
-               if x.outUsed == len(x.fre) {
-                       x.b.Encrypt(x.fre, x.fre)
-                       x.outUsed = 0
-               }
-
-               x.fre[x.outUsed] ^= src[i]
-               dst[i] = x.fre[x.outUsed]
-               x.outUsed++
-       }
-}
-
-type ocfbDecrypter struct {
-       b       Block
-       fre     []byte
-       outUsed int
-}
-
-// NewOCFBDecrypter returns a Stream which decrypts data with OpenPGP's cipher
-// feedback mode using the given Block. Prefix must be the first blockSize + 2
-// bytes of the ciphertext, where blockSize is the Block's block size. If an
-// incorrect key is detected then nil is returned. On successful exit,
-// blockSize+2 bytes of decrypted data are written into prefix. Resync
-// determines if the "resynchronization step" from RFC 4880, 13.9 step 7 is
-// performed. Different parts of OpenPGP vary on this point.
-func NewOCFBDecrypter(block Block, prefix []byte, resync OCFBResyncOption) Stream {
-       blockSize := block.BlockSize()
-       if len(prefix) != blockSize+2 {
-               return nil
-       }
-
-       x := &ocfbDecrypter{
-               b:       block,
-               fre:     make([]byte, blockSize),
-               outUsed: 0,
-       }
-       prefixCopy := make([]byte, len(prefix))
-       copy(prefixCopy, prefix)
-
-       block.Encrypt(x.fre, x.fre)
-       for i := 0; i < blockSize; i++ {
-               prefixCopy[i] ^= x.fre[i]
-       }
-
-       block.Encrypt(x.fre, prefix[:blockSize])
-       prefixCopy[blockSize] ^= x.fre[0]
-       prefixCopy[blockSize+1] ^= x.fre[1]
-
-       if prefixCopy[blockSize-2] != prefixCopy[blockSize] ||
-               prefixCopy[blockSize-1] != prefixCopy[blockSize+1] {
-               return nil
-       }
-
-       if resync {
-               block.Encrypt(x.fre, prefix[2:])
-       } else {
-               x.fre[0] = prefix[blockSize]
-               x.fre[1] = prefix[blockSize+1]
-               x.outUsed = 2
-       }
-       copy(prefix, prefixCopy)
-       return x
-}
-
-func (x *ocfbDecrypter) XORKeyStream(dst, src []byte) {
-       for i := 0; i < len(src); i++ {
-               if x.outUsed == len(x.fre) {
-                       x.b.Encrypt(x.fre, x.fre)
-                       x.outUsed = 0
-               }
-
-               c := src[i]
-               dst[i] = x.fre[x.outUsed] ^ src[i]
-               x.fre[x.outUsed] = c
-               x.outUsed++
-       }
-}
diff --git a/libgo/go/crypto/cipher/ocfb_test.go b/libgo/go/crypto/cipher/ocfb_test.go
deleted file mode 100644 (file)
index 40938b5..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package cipher
-
-import (
-       "bytes"
-       "crypto/aes"
-       "crypto/rand"
-       "testing"
-)
-
-func testOCFB(t *testing.T, resync OCFBResyncOption) {
-       block, err := aes.NewCipher(commonKey128)
-       if err != nil {
-               t.Error(err)
-               return
-       }
-
-       plaintext := []byte("this is the plaintext, which is long enough to span several blocks.")
-       randData := make([]byte, block.BlockSize())
-       rand.Reader.Read(randData)
-       ocfb, prefix := NewOCFBEncrypter(block, randData, resync)
-       ciphertext := make([]byte, len(plaintext))
-       ocfb.XORKeyStream(ciphertext, plaintext)
-
-       ocfbdec := NewOCFBDecrypter(block, prefix, resync)
-       if ocfbdec == nil {
-               t.Errorf("NewOCFBDecrypter failed (resync: %t)", resync)
-               return
-       }
-       plaintextCopy := make([]byte, len(plaintext))
-       ocfbdec.XORKeyStream(plaintextCopy, ciphertext)
-
-       if !bytes.Equal(plaintextCopy, plaintext) {
-               t.Errorf("got: %x, want: %x (resync: %t)", plaintextCopy, plaintext, resync)
-       }
-}
-
-func TestOCFB(t *testing.T) {
-       testOCFB(t, OCFBNoResync)
-       testOCFB(t, OCFBResync)
-}
index c913494f61b92f1f0790ed4905e1757be8a9539f..ecefc6572545ef8d20ffc7500e523b60c2e34277 100644 (file)
@@ -14,15 +14,15 @@ import (
 type Hash uint
 
 const (
-       MD4       Hash = 1 + iota // in package crypto/md4
-       MD5                       // in package crypto/md5
-       SHA1                      // in package crypto/sha1
-       SHA224                    // in package crypto/sha256
-       SHA256                    // in package crypto/sha256
-       SHA384                    // in package crypto/sha512
-       SHA512                    // in package crypto/sha512
+       MD4       Hash = 1 + iota // import code.google.com/p/go.crypto/md4
+       MD5                       // import crypto/md5
+       SHA1                      // import crypto/sha1
+       SHA224                    // import crypto/sha256
+       SHA256                    // import crypto/sha256
+       SHA384                    // import crypto/sha512
+       SHA512                    // import crypto/sha512
        MD5SHA1                   // no implementation; MD5+SHA1 used for TLS RSA
-       RIPEMD160                 // in package crypto/ripemd160
+       RIPEMD160                 // import code.google.com/p/go.crypto/ripemd160
        maxHash
 )
 
@@ -50,8 +50,8 @@ func (h Hash) Size() int {
 
 var hashes = make([]func() hash.Hash, maxHash)
 
-// New returns a new hash.Hash calculating the given hash function. If the
-// hash function is not linked into the binary, New returns nil.
+// New returns a new hash.Hash calculating the given hash function. New panics
+// if the hash function is not linked into the binary.
 func (h Hash) New() hash.Hash {
        if h > 0 && h < maxHash {
                f := hashes[h]
@@ -59,7 +59,12 @@ func (h Hash) New() hash.Hash {
                        return f()
                }
        }
-       return nil
+       panic("crypto: requested hash function is unavailable")
+}
+
+// Available reports whether the given hash function is linked into the binary.
+func (h Hash) Available() bool {
+       return h < maxHash && hashes[h] != nil
 }
 
 // RegisterHash registers a function that returns a new instance of the given
index fc252c8133cb13fd448572caba8848d808fae83a..1c41e29a8bd9fd8af6fb91a8e5ca7c6830ec2689 100644 (file)
@@ -34,13 +34,13 @@ func NewCipher(key []byte) (*Cipher, error) {
 // BlockSize returns the DES block size, 8 bytes.
 func (c *Cipher) BlockSize() int { return BlockSize }
 
-// Encrypts the 8-byte buffer src and stores the result in dst.
+// Encrypt encrypts the 8-byte buffer src and stores the result in dst.
 // Note that for amounts of data larger than a block,
 // it is not safe to just call Encrypt on successive blocks;
 // instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
 func (c *Cipher) Encrypt(dst, src []byte) { encryptBlock(c.subkeys[:], dst, src) }
 
-// Decrypts the 8-byte buffer src and stores the result in dst.
+// Decrypt decrypts the 8-byte buffer src and stores the result in dst.
 func (c *Cipher) Decrypt(dst, src []byte) { decryptBlock(c.subkeys[:], dst, src) }
 
 // Reset zeros the key data, so that it will no longer
index 7aaad1ca19954e53f07cebd14426795125efafeb..81487f68f41160e7c16785b6a014c9eeb88fdd2f 100644 (file)
@@ -102,7 +102,7 @@ GeneratePrimes:
                qBytes[0] |= 0x80
                q.SetBytes(qBytes)
 
-               if !big.ProbablyPrime(q, numMRTests) {
+               if !q.ProbablyPrime(numMRTests) {
                        continue
                }
 
@@ -123,7 +123,7 @@ GeneratePrimes:
                                continue
                        }
 
-                       if !big.ProbablyPrime(p, numMRTests) {
+                       if !p.ProbablyPrime(numMRTests) {
                                continue
                        }
 
index c23af754f78f0aa580c975b530e85253018fba6e..1e3407ee0e7c15f5bcf2f58d0c9450d9966c1400 100644 (file)
@@ -6,6 +6,7 @@ package elliptic
 
 import (
        "crypto/rand"
+       "encoding/hex"
        "fmt"
        "math/big"
        "testing"
@@ -350,3 +351,13 @@ func TestMarshal(t *testing.T) {
                return
        }
 }
+
+func TestP224Overflow(t *testing.T) {
+       // This tests for a specific bug in the P224 implementation.
+       p224 := P224()
+       pointData, _ := hex.DecodeString("049B535B45FB0A2072398A6831834624C7E32CCFD5A4B933BCEAF77F1DD945E08BBE5178F5EDF5E733388F196D2A631D2E075BB16CBFEEA15B")
+       x, y := Unmarshal(p224, pointData)
+       if !p224.IsOnCurve(x, y) {
+               t.Error("P224 failed to validate a correct point")
+       }
+}
index 08db5bcc679f503005e03ff757a7a59df1b8d9e7..17571c252884cc49286061e284320a381a922046 100644 (file)
@@ -225,7 +225,7 @@ func p224ReduceLarge(out *p224FieldElement, in *p224LargeFieldElement) {
                in[i] += p224ZeroModP63[i]
        }
 
-       // Elimintate the coefficients at 2**224 and greater.
+       // Eliminate the coefficients at 2**224 and greater.
        for i := 14; i >= 8; i-- {
                in[i-8] -= in[i]
                in[i-5] += (in[i] & 0xffff) << 12
@@ -288,7 +288,7 @@ func p224Reduce(a *p224FieldElement) {
        a[0] += mask & (1 << 28)
 }
 
-// p224Invert calcuates *out = in**-1 by computing in**(2**224 - 2**96 - 1),
+// p224Invert calculates *out = in**-1 by computing in**(2**224 - 2**96 - 1),
 // i.e. Fermat's little theorem.
 func p224Invert(out, in *p224FieldElement) {
        var f1, f2, f3, f4 p224FieldElement
@@ -341,7 +341,7 @@ func p224Invert(out, in *p224FieldElement) {
 
 // p224Contract converts a FieldElement to its unique, minimal form.
 //
-// On entry, in[i] < 2**32
+// On entry, in[i] < 2**29
 // On exit, in[i] < 2**28
 func p224Contract(out, in *p224FieldElement) {
        copy(out[:], in[:])
@@ -365,6 +365,39 @@ func p224Contract(out, in *p224FieldElement) {
                out[i+1] -= 1 & mask
        }
 
+       // We might have pushed out[3] over 2**28 so we perform another, partial,
+       // carry chain.
+       for i := 3; i < 7; i++ {
+               out[i+1] += out[i] >> 28
+               out[i] &= bottom28Bits
+       }
+       top = out[7] >> 28
+       out[7] &= bottom28Bits
+
+       // Eliminate top while maintaining the same value mod p.
+       out[0] -= top
+       out[3] += top << 12
+
+       // There are two cases to consider for out[3]:
+       //   1) The first time that we eliminated top, we didn't push out[3] over
+       //      2**28. In this case, the partial carry chain didn't change any values
+       //      and top is zero.
+       //   2) We did push out[3] over 2**28 the first time that we eliminated top.
+       //      The first value of top was in [0..16), therefore, prior to eliminating
+       //      the first top, 0xfff1000 <= out[3] <= 0xfffffff. Therefore, after
+       //      overflowing and being reduced by the second carry chain, out[3] <=
+       //      0xf000. Thus it cannot have overflowed when we eliminated top for the
+       //      second time.
+
+       // Again, we may just have made out[0] negative, so do the same carry down.
+       // As before, if we made out[0] negative then we know that out[3] is
+       // sufficiently positive.
+       for i := 0; i < 3; i++ {
+               mask := uint32(int32(out[i]) >> 31)
+               out[i] += (1 << 28) & mask
+               out[i+1] -= 1 & mask
+       }
+
        // Now we see if the value is >= p and, if so, subtract p.
 
        // First we build a mask from the top four limbs, which must all be
index fc5fe6c65e9cb07633948ee01febce582d6bfd75..5391c1829b918275b8ba458516fd1f3f3833aa50 100644 (file)
@@ -39,7 +39,7 @@ func Prime(rand io.Reader, bits int) (p *big.Int, err error) {
                bytes[len(bytes)-1] |= 1
 
                p.SetBytes(bytes)
-               if big.ProbablyPrime(p, 20) {
+               if p.ProbablyPrime(20) {
                        return
                }
        }
index d7b053fec5cc40383d6ed1bee1a741acc9ab34f1..4f12cbea5c5a094e11dbddf764ade2da2aebfad9 100644 (file)
@@ -65,7 +65,7 @@ func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (out [
 // about the plaintext.
 // See ``Chosen Ciphertext Attacks Against Protocols Based on the RSA
 // Encryption Standard PKCS #1'', Daniel Bleichenbacher, Advances in Cryptology
-// (Crypto '98),
+// (Crypto '98).
 func DecryptPKCS1v15SessionKey(rand io.Reader, priv *PrivateKey, ciphertext []byte, key []byte) (err error) {
        k := (priv.N.BitLen() + 7) / 8
        if k-(len(key)+3+8) < 0 {
index c07e8f90db7796f4bf5ae852ab5e9dff6882abf2..677d27be5d27b2aac17db8554b6639077eff0283 100644 (file)
@@ -62,7 +62,7 @@ func (priv *PrivateKey) Validate() error {
        // ProbablyPrime are deterministic, given the candidate number, it's
        // easy for an attack to generate composites that pass this test.
        for _, prime := range priv.Primes {
-               if !big.ProbablyPrime(prime, 20) {
+               if !prime.ProbablyPrime(20) {
                        return errors.New("prime factor is composite")
                }
        }
@@ -85,7 +85,7 @@ func (priv *PrivateKey) Validate() error {
        gcd := new(big.Int)
        x := new(big.Int)
        y := new(big.Int)
-       big.GcdInt(gcd, x, y, totient, e)
+       gcd.GCD(x, y, totient, e)
        if gcd.Cmp(bigOne) != 0 {
                return errors.New("invalid public exponent E")
        }
@@ -156,7 +156,7 @@ NextSetOfPrimes:
                priv.D = new(big.Int)
                y := new(big.Int)
                e := big.NewInt(int64(priv.E))
-               big.GcdInt(g, priv.D, y, e, totient)
+               g.GCD(priv.D, y, e, totient)
 
                if g.Cmp(bigOne) == 0 {
                        priv.D.Add(priv.D, totient)
@@ -284,7 +284,7 @@ func modInverse(a, n *big.Int) (ia *big.Int, ok bool) {
        g := new(big.Int)
        x := new(big.Int)
        y := new(big.Int)
-       big.GcdInt(g, x, y, a, n)
+       g.GCD(x, y, a, n)
        if g.Cmp(bigOne) != 0 {
                // In this case, a and n aren't coprime and we cannot calculate
                // the inverse. This happens because the values of n are nearly
@@ -412,7 +412,7 @@ func decrypt(random io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err er
 }
 
 // DecryptOAEP decrypts ciphertext using RSA-OAEP.
-// If rand != nil, DecryptOAEP uses RSA blinding to avoid timing side-channel attacks.
+// If random != nil, DecryptOAEP uses RSA blinding to avoid timing side-channel attacks.
 func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext []byte, label []byte) (msg []byte, err error) {
        k := (priv.N.BitLen() + 7) / 8
        if len(ciphertext) > k ||
index 632ceea9c1a2adbdfb7261cd373666770d519c6c..687e5ef11b462baab95cf01ce36f1ce74e1fe10d 100644 (file)
@@ -59,7 +59,8 @@ func (c *Conn) clientHandshake() error {
        finishedHash.Write(serverHello.marshal())
 
        vers, ok := mutualVersion(serverHello.vers)
-       if !ok {
+       if !ok || vers < versionTLS10 {
+               // TLS 1.0 is the minimum version supported as a client.
                return c.sendAlert(alertProtocolVersion)
        }
        c.vers = vers
index 28e93a0be69c5165006c89be8f5058004107b43e..9184e8e8118483cf97cdf0bdd84fb0c9dec01b9d 100644 (file)
@@ -33,16 +33,16 @@ func Client(conn net.Conn, config *Config) *Conn {
        return &Conn{conn: conn, config: config, isClient: true}
 }
 
-// A Listener implements a network listener (net.Listener) for TLS connections.
-type Listener struct {
-       listener net.Listener
-       config   *Config
+// A listener implements a network listener (net.Listener) for TLS connections.
+type listener struct {
+       net.Listener
+       config *Config
 }
 
 // Accept waits for and returns the next incoming TLS connection.
 // The returned connection c is a *tls.Conn.
-func (l *Listener) Accept() (c net.Conn, err error) {
-       c, err = l.listener.Accept()
+func (l *listener) Accept() (c net.Conn, err error) {
+       c, err = l.Listener.Accept()
        if err != nil {
                return
        }
@@ -50,28 +50,22 @@ func (l *Listener) Accept() (c net.Conn, err error) {
        return
 }
 
-// Close closes the listener.
-func (l *Listener) Close() error { return l.listener.Close() }
-
-// Addr returns the listener's network address.
-func (l *Listener) Addr() net.Addr { return l.listener.Addr() }
-
 // NewListener creates a Listener which accepts connections from an inner
 // Listener and wraps each connection with Server.
 // The configuration config must be non-nil and must have
 // at least one certificate.
-func NewListener(listener net.Listener, config *Config) (l *Listener) {
-       l = new(Listener)
-       l.listener = listener
+func NewListener(inner net.Listener, config *Config) net.Listener {
+       l := new(listener)
+       l.Listener = inner
        l.config = config
-       return
+       return l
 }
 
 // Listen creates a TLS listener accepting connections on the
 // given network address using net.Listen.
 // The configuration config must be non-nil and must have
 // at least one certificate.
-func Listen(network, laddr string, config *Config) (*Listener, error) {
+func Listen(network, laddr string, config *Config) (net.Listener, error) {
        if config == nil || len(config.Certificates) == 0 {
                return nil, errors.New("tls.Listen: no certificates in configuration")
        }
index 31d0dd0c2264e50ededc180794addbcfccc07c96..3aaa8c5832a26aac09c6d353efa7868269d7557b 100644 (file)
@@ -40,7 +40,7 @@ func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err error) {
        var priv pkcs1PrivateKey
        rest, err := asn1.Unmarshal(der, &priv)
        if len(rest) > 0 {
-               err = asn1.SyntaxError{"trailing data"}
+               err = asn1.SyntaxError{Msg: "trailing data"}
                return
        }
        if err != nil {
index 8eced55f932a01e658ca3615d1b1d772f65bdb1d..738659011fad129d6e321420d0937c520176a8af 100644 (file)
@@ -23,6 +23,8 @@ type RDNSequence []RelativeDistinguishedNameSET
 
 type RelativeDistinguishedNameSET []AttributeTypeAndValue
 
+// AttributeTypeAndValue mirrors the ASN.1 structure of the same name in
+// http://tools.ietf.org/html/rfc5280#section-4.1.2.4
 type AttributeTypeAndValue struct {
        Type  asn1.ObjectIdentifier
        Value interface{}
index 50a3b66e55506a66ab9bea45f07eee93235b3918..87b1cb7bb1c35ecad92703a3ace72c3bba19ab05 100644 (file)
@@ -7,6 +7,7 @@ package x509
 import (
        "strings"
        "time"
+       "unicode/utf8"
 )
 
 type InvalidReason int
@@ -225,17 +226,51 @@ func matchHostnames(pattern, host string) bool {
        return true
 }
 
+// toLowerCaseASCII returns a lower-case version of in. See RFC 6125 6.4.1. We use
+// an explicitly ASCII function to avoid any sharp corners resulting from
+// performing Unicode operations on DNS labels.
+func toLowerCaseASCII(in string) string {
+       // If the string is already lower-case then there's nothing to do.
+       isAlreadyLowerCase := true
+       for _, c := range in {
+               if c == utf8.RuneError {
+                       // If we get a UTF-8 error then there might be
+                       // upper-case ASCII bytes in the invalid sequence.
+                       isAlreadyLowerCase = false
+                       break
+               }
+               if 'A' <= c && c <= 'Z' {
+                       isAlreadyLowerCase = false
+                       break
+               }
+       }
+
+       if isAlreadyLowerCase {
+               return in
+       }
+
+       out := []byte(in)
+       for i, c := range out {
+               if 'A' <= c && c <= 'Z' {
+                       out[i] += 'a' - 'A'
+               }
+       }
+       return string(out)
+}
+
 // VerifyHostname returns nil if c is a valid certificate for the named host.
 // Otherwise it returns an error describing the mismatch.
 func (c *Certificate) VerifyHostname(h string) error {
+       lowered := toLowerCaseASCII(h)
+
        if len(c.DNSNames) > 0 {
                for _, match := range c.DNSNames {
-                       if matchHostnames(match, h) {
+                       if matchHostnames(toLowerCaseASCII(match), lowered) {
                                return nil
                        }
                }
                // If Subject Alt Name is given, we ignore the common name.
-       } else if matchHostnames(c.Subject.CommonName, h) {
+       } else if matchHostnames(toLowerCaseASCII(c.Subject.CommonName), lowered) {
                return nil
        }
 
index 2016858307e275e8ec3f81d6d7be1d9dfd07545b..2cdd66a5589d689531f9e2b2f0f9739867a91dfe 100644 (file)
@@ -37,6 +37,17 @@ var verifyTests = []verifyTest{
                        {"Google", "Thawte", "VeriSign"},
                },
        },
+       {
+               leaf:          googleLeaf,
+               intermediates: []string{thawteIntermediate},
+               roots:         []string{verisignRoot},
+               currentTime:   1302726541,
+               dnsName:       "WwW.GooGLE.coM",
+
+               expectedChains: [][]string{
+                       {"Google", "Thawte", "VeriSign"},
+               },
+       },
        {
                leaf:          googleLeaf,
                intermediates: []string{thawteIntermediate},
index bf39c5dec0af7cdb99cdd56caaea8383bd9e10b4..7b45ba51f43ff995311ba04a503d53835edd70f4 100644 (file)
@@ -592,7 +592,7 @@ func parseCertificate(in *certificate) (*Certificate, error) {
                                        return nil, err
                                }
                                if !seq.IsCompound || seq.Tag != 16 || seq.Class != 0 {
-                                       return nil, asn1.StructuralError{"bad SAN sequence"}
+                                       return nil, asn1.StructuralError{Msg: "bad SAN sequence"}
                                }
 
                                parsedName := false
@@ -744,7 +744,7 @@ func ParseCertificate(asn1Data []byte) (*Certificate, error) {
                return nil, err
        }
        if len(rest) > 0 {
-               return nil, asn1.SyntaxError{"trailing data"}
+               return nil, asn1.SyntaxError{Msg: "trailing data"}
        }
 
        return parseCertificate(&cert)
index e80420e5bb3aa1726f2f031161e18865a16ca123..4924ac14e468c0102beb7abcc436b86e5b09648e 100644 (file)
@@ -49,6 +49,11 @@ func convertAssign(dest, src interface{}) error {
                case *string:
                        *d = string(s)
                        return nil
+               case *interface{}:
+                       bcopy := make([]byte, len(s))
+                       copy(bcopy, s)
+                       *d = bcopy
+                       return nil
                case *[]byte:
                        *d = s
                        return nil
@@ -80,6 +85,9 @@ func convertAssign(dest, src interface{}) error {
                        *d = bv.(bool)
                }
                return err
+       case *interface{}:
+               *d = src
+               return nil
        }
 
        if scanner, ok := dest.(ScannerInto); ok {
index b188864f62328b965872b13f2b40b7e96b0cd9af..34ee93987fc2cbd75748398097703aed8847f403 100644 (file)
@@ -18,14 +18,15 @@ type conversionTest struct {
        s, d interface{} // source and destination
 
        // following are used if they're non-zero
-       wantint  int64
-       wantuint uint64
-       wantstr  string
-       wantf32  float32
-       wantf64  float64
-       wanttime time.Time
-       wantbool bool // used if d is of type *bool
-       wanterr  string
+       wantint   int64
+       wantuint  uint64
+       wantstr   string
+       wantf32   float32
+       wantf64   float64
+       wanttime  time.Time
+       wantbool  bool // used if d is of type *bool
+       wanterr   string
+       wantiface interface{}
 }
 
 // Target variables for scanning into.
@@ -41,6 +42,7 @@ var (
        scanf32    float32
        scanf64    float64
        scantime   time.Time
+       scaniface  interface{}
 )
 
 var conversionTests = []conversionTest{
@@ -95,6 +97,14 @@ var conversionTests = []conversionTest{
        {s: float64(1.5), d: &scanf32, wantf32: float32(1.5)},
        {s: "1.5", d: &scanf32, wantf32: float32(1.5)},
        {s: "1.5", d: &scanf64, wantf64: float64(1.5)},
+
+       // To interface{}
+       {s: float64(1.5), d: &scaniface, wantiface: float64(1.5)},
+       {s: int64(1), d: &scaniface, wantiface: int64(1)},
+       {s: "str", d: &scaniface, wantiface: "str"},
+       {s: []byte("byteslice"), d: &scaniface, wantiface: []byte("byteslice")},
+       {s: true, d: &scaniface, wantiface: true},
+       {s: nil, d: &scaniface},
 }
 
 func intValue(intptr interface{}) int64 {
@@ -152,6 +162,18 @@ func TestConversions(t *testing.T) {
                if !ct.wanttime.IsZero() && !ct.wanttime.Equal(timeValue(ct.d)) {
                        errf("want time %v, got %v", ct.wanttime, timeValue(ct.d))
                }
+               if ifptr, ok := ct.d.(*interface{}); ok {
+                       if !reflect.DeepEqual(ct.wantiface, scaniface) {
+                               errf("want interface %#v, got %#v", ct.wantiface, scaniface)
+                               continue
+                       }
+                       if srcBytes, ok := ct.s.([]byte); ok {
+                               dstBytes := (*ifptr).([]byte)
+                               if &dstBytes[0] == &srcBytes[0] {
+                                       errf("copy into interface{} didn't copy []byte data")
+                               }
+                       }
+               }
        }
 }
 
index 0cd2562d6822d360b58fc663a66da32df04ba861..b930077605047591d3cc40ab3ee4c1ac435fa73e 100644 (file)
@@ -5,7 +5,7 @@
 // Package driver defines interfaces to be implemented by database
 // drivers as used by package sql.
 //
-// Code simply using databases should use package sql.
+// Most code should use package sql.
 //
 // Drivers only need to be aware of a subset of Go's types.  The sql package
 // will convert all types into one of the following:
index df25023e1273f9397ea5522ce2629991592b504c..889e2a25232290562e9373bab72588c0a00ad6c3 100644 (file)
@@ -586,25 +586,25 @@ func converterForType(typ string) driver.ValueConverter {
        case "bool":
                return driver.Bool
        case "nullbool":
-               return driver.Null{driver.Bool}
+               return driver.Null{Converter: driver.Bool}
        case "int32":
                return driver.Int32
        case "string":
-               return driver.NotNull{driver.String}
+               return driver.NotNull{Converter: driver.String}
        case "nullstring":
-               return driver.Null{driver.String}
+               return driver.Null{Converter: driver.String}
        case "int64":
                // TODO(coopernurse): add type-specific converter
-               return driver.NotNull{driver.DefaultParameterConverter}
+               return driver.NotNull{Converter: driver.DefaultParameterConverter}
        case "nullint64":
                // TODO(coopernurse): add type-specific converter
-               return driver.Null{driver.DefaultParameterConverter}
+               return driver.Null{Converter: driver.DefaultParameterConverter}
        case "float64":
                // TODO(coopernurse): add type-specific converter
-               return driver.NotNull{driver.DefaultParameterConverter}
+               return driver.NotNull{Converter: driver.DefaultParameterConverter}
        case "nullfloat64":
                // TODO(coopernurse): add type-specific converter
-               return driver.Null{driver.DefaultParameterConverter}
+               return driver.Null{Converter: driver.DefaultParameterConverter}
        case "datetime":
                return driver.DefaultParameterConverter
        }
index 34a76521050d7600b8f401839a761041eed10b71..436d4953ecd2393251f8d67a57910185668ceb47 100644 (file)
@@ -880,6 +880,10 @@ func (rs *Rows) Columns() ([]string, error) {
 // be modified and held indefinitely. The copy can be avoided by using
 // an argument of type *RawBytes instead; see the documentation for
 // RawBytes for restrictions on its use.
+//
+// If an argument has type *interface{}, Scan copies the value
+// provided by the underlying driver without conversion. If the value
+// is of type []byte, a copy is made and the caller owns the result.
 func (rs *Rows) Scan(dest ...interface{}) error {
        if rs.closed {
                return errors.New("sql: Rows closed")
index c181e43f9798bc893823ace212343bcb60fc9c14..774bee74baacbd67ce8eff74523afdd5fca41c6a 100644 (file)
@@ -24,7 +24,7 @@ type forkableWriter struct {
 }
 
 func newForkableWriter() *forkableWriter {
-       return &forkableWriter{bytes.NewBuffer(nil), nil, nil}
+       return &forkableWriter{new(bytes.Buffer), nil, nil}
 }
 
 func (f *forkableWriter) fork() (pre, post *forkableWriter) {
index c75c7c19d15d15dccb74536bec4420a3e1b6c614..71da6e22b120f8c95c83d8df9b0a41b84aea1c7b 100644 (file)
@@ -125,6 +125,13 @@ func (enc *Encoding) Encode(dst, src []byte) {
        }
 }
 
+// EncodeToString returns the base32 encoding of src.
+func (enc *Encoding) EncodeToString(src []byte) string {
+       buf := make([]byte, enc.EncodedLen(len(src)))
+       enc.Encode(buf, src)
+       return string(buf)
+}
+
 type encoder struct {
        err  error
        enc  *Encoding
@@ -221,24 +228,32 @@ func (e CorruptInputError) Error() string {
 
 // decode is like Decode but returns an additional 'end' value, which
 // indicates if end-of-message padding was encountered and thus any
-// additional data is an error.  decode also assumes len(src)%8==0,
-// since it is meant for internal use.
+// additional data is an error.
 func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
-       for i := 0; i < len(src)/8 && !end; i++ {
+       osrc := src
+       for len(src) > 0 && !end {
                // Decode quantum using the base32 alphabet
                var dbuf [8]byte
                dlen := 8
 
                // do the top bytes contain any data?
        dbufloop:
-               for j := 0; j < 8; j++ {
-                       in := src[i*8+j]
-                       if in == '=' && j >= 2 && i == len(src)/8-1 {
+               for j := 0; j < 8; {
+                       if len(src) == 0 {
+                               return n, false, CorruptInputError(len(osrc) - len(src) - j)
+                       }
+                       in := src[0]
+                       src = src[1:]
+                       if in == '\r' || in == '\n' {
+                               // Ignore this character.
+                               continue
+                       }
+                       if in == '=' && j >= 2 && len(src) < 8 {
                                // We've reached the end and there's
                                // padding, the rest should be padded
-                               for k := j; k < 8; k++ {
-                                       if src[i*8+k] != '=' {
-                                               return n, false, CorruptInputError(i*8 + j)
+                               for k := 0; k < 8-j-1; k++ {
+                                       if len(src) > k && src[k] != '=' {
+                                               return n, false, CorruptInputError(len(osrc) - len(src) + k - 1)
                                        }
                                }
                                dlen = j
@@ -247,28 +262,30 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
                        }
                        dbuf[j] = enc.decodeMap[in]
                        if dbuf[j] == 0xFF {
-                               return n, false, CorruptInputError(i*8 + j)
+                               return n, false, CorruptInputError(len(osrc) - len(src) - 1)
                        }
+                       j++
                }
 
                // Pack 8x 5-bit source blocks into 5 byte destination
                // quantum
                switch dlen {
                case 7, 8:
-                       dst[i*5+4] = dbuf[6]<<5 | dbuf[7]
+                       dst[4] = dbuf[6]<<5 | dbuf[7]
                        fallthrough
                case 6, 5:
-                       dst[i*5+3] = dbuf[4]<<7 | dbuf[5]<<2 | dbuf[6]>>3
+                       dst[3] = dbuf[4]<<7 | dbuf[5]<<2 | dbuf[6]>>3
                        fallthrough
                case 4:
-                       dst[i*5+2] = dbuf[3]<<4 | dbuf[4]>>1
+                       dst[2] = dbuf[3]<<4 | dbuf[4]>>1
                        fallthrough
                case 3:
-                       dst[i*5+1] = dbuf[1]<<6 | dbuf[2]<<1 | dbuf[3]>>4
+                       dst[1] = dbuf[1]<<6 | dbuf[2]<<1 | dbuf[3]>>4
                        fallthrough
                case 2:
-                       dst[i*5+0] = dbuf[0]<<3 | dbuf[1]>>2
+                       dst[0] = dbuf[0]<<3 | dbuf[1]>>2
                }
+               dst = dst[5:]
                switch dlen {
                case 2:
                        n += 1
@@ -289,15 +306,19 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
 // DecodedLen(len(src)) bytes to dst and returns the number of bytes
 // written.  If src contains invalid base32 data, it will return the
 // number of bytes successfully written and CorruptInputError.
+// New line characters (\r and \n) are ignored.
 func (enc *Encoding) Decode(dst, src []byte) (n int, err error) {
-       if len(src)%8 != 0 {
-               return 0, CorruptInputError(len(src) / 8 * 8)
-       }
-
        n, _, err = enc.decode(dst, src)
        return
 }
 
+// DecodeString returns the bytes represented by the base32 string s.
+func (enc *Encoding) DecodeString(s string) ([]byte, error) {
+       dbuf := make([]byte, enc.DecodedLen(len(s)))
+       n, err := enc.Decode(dbuf, []byte(s))
+       return dbuf[:n], err
+}
+
 type decoder struct {
        err    error
        enc    *Encoding
index facf5d04eeb11dbac9c05e580729bfa1d8e612ef..98365e18cfc9f28927e911444b1b0eb4fc75bb60 100644 (file)
@@ -51,9 +51,8 @@ func testEqual(t *testing.T, msg string, args ...interface{}) bool {
 
 func TestEncode(t *testing.T) {
        for _, p := range pairs {
-               buf := make([]byte, StdEncoding.EncodedLen(len(p.decoded)))
-               StdEncoding.Encode(buf, []byte(p.decoded))
-               testEqual(t, "Encode(%q) = %q, want %q", p.decoded, string(buf), p.encoded)
+               got := StdEncoding.EncodeToString([]byte(p.decoded))
+               testEqual(t, "Encode(%q) = %q, want %q", p.decoded, got, p.encoded)
        }
 }
 
@@ -99,6 +98,10 @@ func TestDecode(t *testing.T) {
                testEqual(t, "Decode(%q) = %q, want %q", p.encoded,
                        string(dbuf[0:count]),
                        p.decoded)
+
+               dbuf, err = StdEncoding.DecodeString(p.encoded)
+               testEqual(t, "DecodeString(%q) = error %v, want %v", p.encoded, err, error(nil))
+               testEqual(t, "DecodeString(%q) = %q, want %q", p.encoded, string(dbuf), p.decoded)
        }
 }
 
@@ -191,3 +194,29 @@ func TestBig(t *testing.T) {
                t.Errorf("Decode(Encode(%d-byte string)) failed at offset %d", n, i)
        }
 }
+
+func TestNewLineCharacters(t *testing.T) {
+       // Each of these should decode to the string "sure", without errors.
+       const expected = "sure"
+       examples := []string{
+               "ON2XEZI=",
+               "ON2XEZI=\r",
+               "ON2XEZI=\n",
+               "ON2XEZI=\r\n",
+               "ON2XEZ\r\nI=",
+               "ON2X\rEZ\nI=",
+               "ON2X\nEZ\rI=",
+               "ON2XEZ\nI=",
+               "ON2XEZI\n=",
+       }
+       for _, e := range examples {
+               buf, err := StdEncoding.DecodeString(e)
+               if err != nil {
+                       t.Errorf("Decode(%q) failed: %v", e, err)
+                       continue
+               }
+               if s := string(buf); s != expected {
+                       t.Errorf("Decode(%q) = %q, want %q", e, s, expected)
+               }
+       }
+}
index 889b565e3f5a475b6c86672b5af6184c030c2c4c..55f9f67a43a566bcd466193dc1404a4f55ee7aae 100644 (file)
@@ -208,22 +208,30 @@ func (e CorruptInputError) Error() string {
 
 // decode is like Decode but returns an additional 'end' value, which
 // indicates if end-of-message padding was encountered and thus any
-// additional data is an error.  decode also assumes len(src)%4==0,
-// since it is meant for internal use.
+// additional data is an error.
 func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
-       for i := 0; i < len(src)/4 && !end; i++ {
+       osrc := src
+       for len(src) > 0 && !end {
                // Decode quantum using the base64 alphabet
                var dbuf [4]byte
                dlen := 4
 
        dbufloop:
-               for j := 0; j < 4; j++ {
-                       in := src[i*4+j]
-                       if in == '=' && j >= 2 && i == len(src)/4-1 {
+               for j := 0; j < 4; {
+                       if len(src) == 0 {
+                               return n, false, CorruptInputError(len(osrc) - len(src) - j)
+                       }
+                       in := src[0]
+                       src = src[1:]
+                       if in == '\r' || in == '\n' {
+                               // Ignore this character.
+                               continue
+                       }
+                       if in == '=' && j >= 2 && len(src) < 4 {
                                // We've reached the end and there's
                                // padding
-                               if src[i*4+3] != '=' {
-                                       return n, false, CorruptInputError(i*4 + 2)
+                               if len(src) > 0 && src[0] != '=' {
+                                       return n, false, CorruptInputError(len(osrc) - len(src) - 1)
                                }
                                dlen = j
                                end = true
@@ -231,22 +239,24 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
                        }
                        dbuf[j] = enc.decodeMap[in]
                        if dbuf[j] == 0xFF {
-                               return n, false, CorruptInputError(i*4 + j)
+                               return n, false, CorruptInputError(len(osrc) - len(src) - 1)
                        }
+                       j++
                }
 
                // Pack 4x 6-bit source blocks into 3 byte destination
                // quantum
                switch dlen {
                case 4:
-                       dst[i*3+2] = dbuf[2]<<6 | dbuf[3]
+                       dst[2] = dbuf[2]<<6 | dbuf[3]
                        fallthrough
                case 3:
-                       dst[i*3+1] = dbuf[1]<<4 | dbuf[2]>>2
+                       dst[1] = dbuf[1]<<4 | dbuf[2]>>2
                        fallthrough
                case 2:
-                       dst[i*3+0] = dbuf[0]<<2 | dbuf[1]>>4
+                       dst[0] = dbuf[0]<<2 | dbuf[1]>>4
                }
+               dst = dst[3:]
                n += dlen - 1
        }
 
@@ -257,11 +267,8 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
 // DecodedLen(len(src)) bytes to dst and returns the number of bytes
 // written.  If src contains invalid base64 data, it will return the
 // number of bytes successfully written and CorruptInputError.
+// New line characters (\r and \n) are ignored.
 func (enc *Encoding) Decode(dst, src []byte) (n int, err error) {
-       if len(src)%4 != 0 {
-               return 0, CorruptInputError(len(src) / 4 * 4)
-       }
-
        n, _, err = enc.decode(dst, src)
        return
 }
index 8310d8ab9e3d1a0cce7a55ce1425ec3085bc7216..3e9a84393b60150f22eb88d0bc60342daeba82c1 100644 (file)
@@ -197,3 +197,29 @@ func TestBig(t *testing.T) {
                t.Errorf("Decode(Encode(%d-byte string)) failed at offset %d", n, i)
        }
 }
+
+func TestNewLineCharacters(t *testing.T) {
+       // Each of these should decode to the string "sure", without errors.
+       const expected = "sure"
+       examples := []string{
+               "c3VyZQ==",
+               "c3VyZQ==\r",
+               "c3VyZQ==\n",
+               "c3VyZQ==\r\n",
+               "c3VyZ\r\nQ==",
+               "c3V\ryZ\nQ==",
+               "c3V\nyZ\rQ==",
+               "c3VyZ\nQ==",
+               "c3VyZQ\n==",
+       }
+       for _, e := range examples {
+               buf, err := StdEncoding.DecodeString(e)
+               if err != nil {
+                       t.Errorf("Decode(%q) failed: %v", e, err)
+                       continue
+               }
+               if s := string(buf); s != expected {
+                       t.Errorf("Decode(%q) = %q, want %q", e, s, expected)
+               }
+       }
+}
index d2f8b1e62483efc39a4d929b4fe860bab5154c91..4be83f53bd489f51f9b84b7ac3cb3bf835663e1d 100644 (file)
@@ -163,7 +163,7 @@ func Read(r io.Reader, order ByteOrder, data interface{}) error {
        default:
                return errors.New("binary.Read: invalid type " + d.Type().String())
        }
-       size := TotalSize(v)
+       size := dataSize(v)
        if size < 0 {
                return errors.New("binary.Read: invalid type " + v.Type().String())
        }
@@ -242,7 +242,7 @@ func Write(w io.Writer, order ByteOrder, data interface{}) error {
                return err
        }
        v := reflect.Indirect(reflect.ValueOf(data))
-       size := TotalSize(v)
+       size := dataSize(v)
        if size < 0 {
                return errors.New("binary.Write: invalid type " + v.Type().String())
        }
@@ -253,7 +253,11 @@ func Write(w io.Writer, order ByteOrder, data interface{}) error {
        return err
 }
 
-func TotalSize(v reflect.Value) int {
+// dataSize returns the number of bytes the actual data represented by v occupies in memory.
+// For compound structures, it sums the sizes of the elements. Thus, for instance, for a slice
+// it returns the length of the slice times the element size and does not count the memory
+// occupied by the header.
+func dataSize(v reflect.Value) int {
        if v.Kind() == reflect.Slice {
                elem := sizeof(v.Type().Elem())
                if elem < 0 {
index 3e7057ea22787066f2054d82f30ef0b92adbc7ff..ff361b7e379f93a740246dc451596299f404568a 100644 (file)
@@ -187,7 +187,7 @@ func BenchmarkReadStruct(b *testing.B) {
        bsr := &byteSliceReader{}
        var buf bytes.Buffer
        Write(&buf, BigEndian, &s)
-       n := TotalSize(reflect.ValueOf(s))
+       n := dataSize(reflect.ValueOf(s))
        b.SetBytes(int64(n))
        t := s
        b.ResetTimer()
index ae0f567b9df811c241a5a0b47cabd2dfe22e8c33..9aa398e58b28d30efc77ea4b0c53b0b440c5b5d3 100644 (file)
@@ -156,6 +156,9 @@ func (r *Reader) Read() (record []string, err error) {
 
 // ReadAll reads all the remaining records from r.
 // Each record is a slice of fields.
+// A successful call returns err == nil, not err == EOF. Because ReadAll is
+// defined to read until EOF, it does not treat end of file as an error to be
+// reported.
 func (r *Reader) ReadAll() (records [][]string, err error) {
        for {
                record, err := r.Read()
index 73844b920c14bfa00fced5fd73ffc80df749ec73..d365f82634553912242a3d27d8b657434d3ce179 100644 (file)
@@ -8,9 +8,11 @@ import (
        "bytes"
        "errors"
        "math"
+       "math/rand"
        "reflect"
        "strings"
        "testing"
+       "time"
        "unsafe"
 )
 
@@ -1407,3 +1409,60 @@ func TestDebugStruct(t *testing.T) {
        }
        debugFunc(debugBuffer)
 }
+
+func encFuzzDec(rng *rand.Rand, in interface{}) error {
+       buf := new(bytes.Buffer)
+       enc := NewEncoder(buf)
+       if err := enc.Encode(&in); err != nil {
+               return err
+       }
+
+       b := buf.Bytes()
+       for i, bi := range b {
+               if rng.Intn(10) < 3 {
+                       b[i] = bi + uint8(rng.Intn(256))
+               }
+       }
+
+       dec := NewDecoder(buf)
+       var e interface{}
+       if err := dec.Decode(&e); err != nil {
+               return err
+       }
+       return nil
+}
+
+// This does some "fuzz testing" by attempting to decode a sequence of random bytes.
+func TestFuzz(t *testing.T) {
+       if testing.Short() {
+               return
+       }
+
+       // all possible inputs
+       input := []interface{}{
+               new(int),
+               new(float32),
+               new(float64),
+               new(complex128),
+               &ByteStruct{255},
+               &ArrayStruct{},
+               &StringStruct{"hello"},
+               &GobTest1{0, &StringStruct{"hello"}},
+       }
+       testFuzz(t, time.Now().UnixNano(), 100, input...)
+}
+
+func TestFuzzRegressions(t *testing.T) {
+       // An instance triggering a type name of length ~102 GB.
+       testFuzz(t, 1328492090837718000, 100, new(float32))
+}
+
+func testFuzz(t *testing.T, seed int64, n int, input ...interface{}) {
+       t.Logf("seed=%d n=%d\n", seed, n)
+       for _, e := range input {
+               rng := rand.New(rand.NewSource(seed))
+               for i := 0; i < n; i++ {
+                       encFuzzDec(rng, e)
+               }
+       }
+}
index 6dc7fc9aca0604d523ee262ce55328fe6004fad0..b54ef46f52c29b72b1c87e016b7b7f149edc4dd5 100644 (file)
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Delete the next line to include this file in the gob package.
-// +build ignore
+// Delete the next line to include in the gob package.
+// +build gob-debug
 
 package gob
 
index 4d1325d176c61cc0455047559e36725c17cfb1ed..8191062d30930303a85086c539c6b962735316bd 100644 (file)
@@ -690,7 +690,11 @@ func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, p ui
        // Create a writable interface reflect.Value.  We need one even for the nil case.
        ivalue := allocValue(ityp)
        // Read the name of the concrete type.
-       b := make([]byte, state.decodeUint())
+       nr := state.decodeUint()
+       if nr < 0 || nr > 1<<31 { // zero is permissible for anonymous types
+               errorf("invalid type name length %d", nr)
+       }
+       b := make([]byte, nr)
        state.b.Read(b)
        name := string(b)
        if name == "" {
index fb28c8caf53561f24791fbef614e5d4a168d3947..c5c7d3fdb10ddc7d3c4f1defb703d839a7d1e3db 100644 (file)
@@ -135,7 +135,7 @@ func (dec *Decoder) nextUint() uint64 {
 // and returns the type id of the next value.  It returns -1 at
 // EOF.  Upon return, the remainder of dec.buf is the value to be
 // decoded.  If this is an interface value, it can be ignored by
-// simply resetting that buffer.
+// resetting that buffer.
 func (dec *Decoder) decodeTypeSequence(isInterface bool) typeId {
        for dec.err == nil {
                if dec.buf.Len() == 0 {
index 05ebef195932775e2e99962ef38cc09d05fe4900..c9ad18e764199a243e7386bd0680692cf4400698 100644 (file)
@@ -70,7 +70,7 @@ operation will fail.
 Structs, arrays and slices are also supported.  Strings and arrays of bytes are
 supported with a special, efficient representation (see below).  When a slice is
 decoded, if the existing slice has capacity the slice will be extended in place;
-if not, a new array is allocated.  Regardless, the length of the resuling slice
+if not, a new array is allocated.  Regardless, the length of the resulting slice
 reports the number of elements decoded.
 
 Functions and channels cannot be sent in a gob.  Attempting
@@ -162,7 +162,7 @@ description, constructed from these types:
                StructT *StructType
                MapT    *MapType
        }
-       type ArrayType struct {
+       type arrayType struct {
                CommonType
                Elem typeId
                Len  int
@@ -171,19 +171,19 @@ description, constructed from these types:
                Name string // the name of the struct type
                Id  int    // the id of the type, repeated so it's inside the type
        }
-       type SliceType struct {
+       type sliceType struct {
                CommonType
                Elem typeId
        }
-       type StructType struct {
+       type structType struct {
                CommonType
                Field []*fieldType // the fields of the struct.
        }
-       type FieldType struct {
+       type fieldType struct {
                Name string // the name of the field.
                Id   int    // the type id of the field, which must be already defined
        }
-       type MapType struct {
+       type mapType struct {
                CommonType
                Key  typeId
                Elem typeId
@@ -308,15 +308,15 @@ reserved).
        // Set the field number implicitly to -1; this is done at the beginning
        // of every struct, including nested structs.
        03      // Add 3 to field number; now 2 (wireType.structType; this is a struct).
-               // structType starts with an embedded commonType, which appears
+               // structType starts with an embedded CommonType, which appears
                // as a regular structure here too.
-       01      // add 1 to field number (now 0); start of embedded commonType.
+       01      // add 1 to field number (now 0); start of embedded CommonType.
        01      // add 1 to field number (now 0, the name of the type)
        05      // string is (unsigned) 5 bytes long
-       50 6f 69 6e 74  // wireType.structType.commonType.name = "Point"
+       50 6f 69 6e 74  // wireType.structType.CommonType.name = "Point"
        01      // add 1 to field number (now 1, the id of the type)
-       ff 82   // wireType.structType.commonType._id = 65
-       00      // end of embedded wiretype.structType.commonType struct
+       ff 82   // wireType.structType.CommonType._id = 65
+       00      // end of embedded wiretype.structType.CommonType struct
        01      // add 1 to field number (now 1, the field array in wireType.structType)
        02      // There are two fields in the type (len(structType.field))
        01      // Start of first field structure; add 1 to get field number 0: field[0].name
index 7a30f9107e636638e6d666fce46792d5bb639be2..9a62cf9c2ade63cf7aa658fe4c20facd5c8d4394 100644 (file)
@@ -570,8 +570,7 @@ func TestGobMapInterfaceEncode(t *testing.T) {
                "bo": []bool{false},
                "st": []string{"s"},
        }
-       buf := bytes.NewBuffer(nil)
-       enc := NewEncoder(buf)
+       enc := NewEncoder(new(bytes.Buffer))
        err := enc.Encode(m)
        if err != nil {
                t.Errorf("encode map: %s", err)
@@ -579,7 +578,7 @@ func TestGobMapInterfaceEncode(t *testing.T) {
 }
 
 func TestSliceReusesMemory(t *testing.T) {
-       buf := bytes.NewBuffer(nil)
+       buf := new(bytes.Buffer)
        // Bytes
        {
                x := []byte("abcd")
index fbae8b683da74038a930e055219246e278b6ee88..92cc0c615e3bd94bd286700ac510705c5b1cac2a 100644 (file)
@@ -33,7 +33,11 @@ func error_(err error) {
 // plain error.  It overwrites the error return of the function that deferred its call.
 func catchError(err *error) {
        if e := recover(); e != nil {
-               *err = e.(gobError).err // Will re-panic if not one of our errors, such as a runtime error.
+               ge, ok := e.(gobError)
+               if !ok {
+                       panic(e)
+               }
+               *err = ge.err
        }
        return
 }
index 1017eb7f51d4100a8df8070360ef208b12b50c9a..b9371c42309eec79e858001e423ac106afcc1468 100644 (file)
@@ -53,8 +53,9 @@ func TestCountEncodeMallocs(t *testing.T) {
        var buf bytes.Buffer
        enc := NewEncoder(&buf)
        bench := &Bench{7, 3.2, "now is the time", []byte("for all good men")}
-       runtime.UpdateMemStats()
-       mallocs := 0 - runtime.MemStats.Mallocs
+       memstats := new(runtime.MemStats)
+       runtime.ReadMemStats(memstats)
+       mallocs := 0 - memstats.Mallocs
        const count = 1000
        for i := 0; i < count; i++ {
                err := enc.Encode(bench)
@@ -62,8 +63,8 @@ func TestCountEncodeMallocs(t *testing.T) {
                        t.Fatal("encode:", err)
                }
        }
-       runtime.UpdateMemStats()
-       mallocs += runtime.MemStats.Mallocs
+       runtime.ReadMemStats(memstats)
+       mallocs += memstats.Mallocs
        fmt.Printf("mallocs per encode of type Bench: %d\n", mallocs/count)
 }
 
@@ -79,8 +80,9 @@ func TestCountDecodeMallocs(t *testing.T) {
                }
        }
        dec := NewDecoder(&buf)
-       runtime.UpdateMemStats()
-       mallocs := 0 - runtime.MemStats.Mallocs
+       memstats := new(runtime.MemStats)
+       runtime.ReadMemStats(memstats)
+       mallocs := 0 - memstats.Mallocs
        for i := 0; i < count; i++ {
                *bench = Bench{}
                err := dec.Decode(&bench)
@@ -88,7 +90,7 @@ func TestCountDecodeMallocs(t *testing.T) {
                        t.Fatal("decode:", err)
                }
        }
-       runtime.UpdateMemStats()
-       mallocs += runtime.MemStats.Mallocs
+       runtime.ReadMemStats(memstats)
+       mallocs += memstats.Mallocs
        fmt.Printf("mallocs per decode of type Bench: %d\n", mallocs/count)
 }
index 71a28be7cab8a7a497145f9fdd692f95ab5dadc8..39006efdb2d596a553899fa778df42cb1e91cd84 100644 (file)
@@ -180,7 +180,10 @@ func (t typeId) name() string {
        return t.gobType().name()
 }
 
-// Common elements of all types.
+// CommonType holds elements of all types.
+// It is a historical artifact, kept for binary compatibility and exported
+// only for the benefit of the package's encoding of type descriptors. It is
+// not intended for direct use by clients.
 type CommonType struct {
        Name string
        Id   typeId
index eb7e7ca8d3878cebd044070fdd6ba84ea1dabdb8..167d00e032aec9a56be8fb728fc415426d54bdc4 100644 (file)
@@ -7,8 +7,9 @@ package hex
 
 import (
        "bytes"
+       "errors"
+       "fmt"
        "io"
-       "strconv"
 )
 
 const hextable = "0123456789abcdef"
@@ -29,16 +30,14 @@ func Encode(dst, src []byte) int {
        return len(src) * 2
 }
 
-// OddLengthInputError results from decoding an odd length slice.
-type OddLengthInputError struct{}
+// ErrLength results from decoding an odd length slice.
+var ErrLength = errors.New("encoding/hex: odd length hex string")
 
-func (OddLengthInputError) Error() string { return "odd length hex string" }
+// InvalidByteError values describe errors resulting from an invalid byte in a hex string.
+type InvalidByteError byte
 
-// InvalidHexCharError results from finding an invalid character in a hex string.
-type InvalidHexCharError byte
-
-func (e InvalidHexCharError) Error() string {
-       return "invalid hex char: " + strconv.Itoa(int(e))
+func (e InvalidByteError) Error() string {
+       return fmt.Sprintf("encoding/hex: invalid byte: %#U", rune(e))
 }
 
 func DecodedLen(x int) int { return x / 2 }
@@ -46,21 +45,20 @@ func DecodedLen(x int) int { return x / 2 }
 // Decode decodes src into DecodedLen(len(src)) bytes, returning the actual
 // number of bytes written to dst.
 //
-// If Decode encounters invalid input, it returns an OddLengthInputError or an
-// InvalidHexCharError.
+// If Decode encounters invalid input, it returns an error describing the failure.
 func Decode(dst, src []byte) (int, error) {
        if len(src)%2 == 1 {
-               return 0, OddLengthInputError{}
+               return 0, ErrLength
        }
 
        for i := 0; i < len(src)/2; i++ {
                a, ok := fromHexChar(src[i*2])
                if !ok {
-                       return 0, InvalidHexCharError(src[i*2])
+                       return 0, InvalidByteError(src[i*2])
                }
                b, ok := fromHexChar(src[i*2+1])
                if !ok {
-                       return 0, InvalidHexCharError(src[i*2+1])
+                       return 0, InvalidByteError(src[i*2+1])
                }
                dst[i] = (a << 4) | b
        }
@@ -103,8 +101,8 @@ func DecodeString(s string) ([]byte, error) {
 // Dump returns a string that contains a hex dump of the given data. The format
 // of the hex dump matches the output of `hexdump -C` on the command line.
 func Dump(data []byte) string {
-       buf := bytes.NewBuffer(nil)
-       dumper := Dumper(buf)
+       var buf bytes.Buffer
+       dumper := Dumper(&buf)
        dumper.Write(data)
        dumper.Close()
        return string(buf.Bytes())
index 8e1838e51e6f4c2b2562f74b2e462ec75f47462a..2d24fd0a146109adcaf87e7a2d1122060fc0c7aa 100644 (file)
@@ -9,141 +9,98 @@ import (
        "testing"
 )
 
-type encodeTest struct {
-       in, out []byte
+type encDecTest struct {
+       enc string
+       dec []byte
 }
 
-var encodeTests = []encodeTest{
-       {[]byte{}, []byte{}},
-       {[]byte{0x01}, []byte{'0', '1'}},
-       {[]byte{0xff}, []byte{'f', 'f'}},
-       {[]byte{0xff, 00}, []byte{'f', 'f', '0', '0'}},
-       {[]byte{0}, []byte{'0', '0'}},
-       {[]byte{1}, []byte{'0', '1'}},
-       {[]byte{2}, []byte{'0', '2'}},
-       {[]byte{3}, []byte{'0', '3'}},
-       {[]byte{4}, []byte{'0', '4'}},
-       {[]byte{5}, []byte{'0', '5'}},
-       {[]byte{6}, []byte{'0', '6'}},
-       {[]byte{7}, []byte{'0', '7'}},
-       {[]byte{8}, []byte{'0', '8'}},
-       {[]byte{9}, []byte{'0', '9'}},
-       {[]byte{10}, []byte{'0', 'a'}},
-       {[]byte{11}, []byte{'0', 'b'}},
-       {[]byte{12}, []byte{'0', 'c'}},
-       {[]byte{13}, []byte{'0', 'd'}},
-       {[]byte{14}, []byte{'0', 'e'}},
-       {[]byte{15}, []byte{'0', 'f'}},
+var encDecTests = []encDecTest{
+       {"", []byte{}},
+       {"0001020304050607", []byte{0, 1, 2, 3, 4, 5, 6, 7}},
+       {"08090a0b0c0d0e0f", []byte{8, 9, 10, 11, 12, 13, 14, 15}},
+       {"f0f1f2f3f4f5f6f7", []byte{0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7}},
+       {"f8f9fafbfcfdfeff", []byte{0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff}},
+       {"67", []byte{'g'}},
+       {"e3a1", []byte{0xe3, 0xa1}},
 }
 
 func TestEncode(t *testing.T) {
-       for i, test := range encodeTests {
-               dst := make([]byte, EncodedLen(len(test.in)))
-               n := Encode(dst, test.in)
+       for i, test := range encDecTests {
+               dst := make([]byte, EncodedLen(len(test.dec)))
+               n := Encode(dst, test.dec)
                if n != len(dst) {
                        t.Errorf("#%d: bad return value: got: %d want: %d", i, n, len(dst))
                }
-               if bytes.Compare(dst, test.out) != 0 {
-                       t.Errorf("#%d: got: %#v want: %#v", i, dst, test.out)
+               if string(dst) != test.enc {
+                       t.Errorf("#%d: got: %#v want: %#v", i, dst, test.enc)
                }
        }
 }
 
-type decodeTest struct {
-       in, out []byte
-       ok      bool
-}
-
-var decodeTests = []decodeTest{
-       {[]byte{}, []byte{}, true},
-       {[]byte{'0'}, []byte{}, false},
-       {[]byte{'0', 'g'}, []byte{}, false},
-       {[]byte{'0', '\x01'}, []byte{}, false},
-       {[]byte{'0', '0'}, []byte{0}, true},
-       {[]byte{'0', '1'}, []byte{1}, true},
-       {[]byte{'0', '2'}, []byte{2}, true},
-       {[]byte{'0', '3'}, []byte{3}, true},
-       {[]byte{'0', '4'}, []byte{4}, true},
-       {[]byte{'0', '5'}, []byte{5}, true},
-       {[]byte{'0', '6'}, []byte{6}, true},
-       {[]byte{'0', '7'}, []byte{7}, true},
-       {[]byte{'0', '8'}, []byte{8}, true},
-       {[]byte{'0', '9'}, []byte{9}, true},
-       {[]byte{'0', 'a'}, []byte{10}, true},
-       {[]byte{'0', 'b'}, []byte{11}, true},
-       {[]byte{'0', 'c'}, []byte{12}, true},
-       {[]byte{'0', 'd'}, []byte{13}, true},
-       {[]byte{'0', 'e'}, []byte{14}, true},
-       {[]byte{'0', 'f'}, []byte{15}, true},
-       {[]byte{'0', 'A'}, []byte{10}, true},
-       {[]byte{'0', 'B'}, []byte{11}, true},
-       {[]byte{'0', 'C'}, []byte{12}, true},
-       {[]byte{'0', 'D'}, []byte{13}, true},
-       {[]byte{'0', 'E'}, []byte{14}, true},
-       {[]byte{'0', 'F'}, []byte{15}, true},
-}
-
 func TestDecode(t *testing.T) {
-       for i, test := range decodeTests {
-               dst := make([]byte, DecodedLen(len(test.in)))
-               n, err := Decode(dst, test.in)
-               if err == nil && n != len(dst) {
+       for i, test := range encDecTests {
+               dst := make([]byte, DecodedLen(len(test.enc)))
+               n, err := Decode(dst, []byte(test.enc))
+               if err != nil {
                        t.Errorf("#%d: bad return value: got:%d want:%d", i, n, len(dst))
-               }
-               if test.ok != (err == nil) {
-                       t.Errorf("#%d: unexpected err value: %s", i, err)
-               }
-               if err == nil && bytes.Compare(dst, test.out) != 0 {
-                       t.Errorf("#%d: got: %#v want: %#v", i, dst, test.out)
+               } else if !bytes.Equal(dst, test.dec) {
+                       t.Errorf("#%d: got: %#v want: %#v", i, dst, test.dec)
                }
        }
 }
 
-type encodeStringTest struct {
-       in  []byte
-       out string
-}
-
-var encodeStringTests = []encodeStringTest{
-       {[]byte{}, ""},
-       {[]byte{0}, "00"},
-       {[]byte{0, 1}, "0001"},
-       {[]byte{0, 1, 255}, "0001ff"},
+func TestEncodeToString(t *testing.T) {
+       for i, test := range encDecTests {
+               s := EncodeToString(test.dec)
+               if s != test.enc {
+                       t.Errorf("#%d got:%s want:%s", i, s, test.enc)
+               }
+       }
 }
 
-func TestEncodeToString(t *testing.T) {
-       for i, test := range encodeStringTests {
-               s := EncodeToString(test.in)
-               if s != test.out {
-                       t.Errorf("#%d got:%s want:%s", i, s, test.out)
+func TestDecodeString(t *testing.T) {
+       for i, test := range encDecTests {
+               dst, err := DecodeString(test.enc)
+               if err != nil {
+                       t.Errorf("#%d: unexpected err value: %s", i, err)
+                       continue
+               }
+               if bytes.Compare(dst, test.dec) != 0 {
+                       t.Errorf("#%d: got: %#v want: #%v", i, dst, test.dec)
                }
        }
 }
 
-type decodeStringTest struct {
+type errTest struct {
        in  string
-       out []byte
-       ok  bool
+       err string
 }
 
-var decodeStringTests = []decodeStringTest{
-       {"", []byte{}, true},
-       {"0", []byte{}, false},
-       {"00", []byte{0}, true},
-       {"0\x01", []byte{}, false},
-       {"0g", []byte{}, false},
-       {"00ff00", []byte{0, 255, 0}, true},
-       {"0000ff", []byte{0, 0, 255}, true},
+var errTests = []errTest{
+       {"0", "encoding/hex: odd length hex string"},
+       {"0g", "encoding/hex: invalid byte: U+0067 'g'"},
+       {"0\x01", "encoding/hex: invalid byte: U+0001"},
 }
 
-func TestDecodeString(t *testing.T) {
-       for i, test := range decodeStringTests {
-               dst, err := DecodeString(test.in)
-               if test.ok != (err == nil) {
-                       t.Errorf("#%d: unexpected err value: %s", i, err)
+func TestInvalidErr(t *testing.T) {
+       for i, test := range errTests {
+               dst := make([]byte, DecodedLen(len(test.in)))
+               _, err := Decode(dst, []byte(test.in))
+               if err == nil {
+                       t.Errorf("#%d: expected error; got none")
+               } else if err.Error() != test.err {
+                       t.Errorf("#%d: got: %v want: %v", i, err, test.err)
                }
-               if err == nil && bytes.Compare(dst, test.out) != 0 {
-                       t.Errorf("#%d: got: %#v want: #%v", i, dst, test.out)
+       }
+}
+
+func TestInvalidStringErr(t *testing.T) {
+       for i, test := range errTests {
+               _, err := DecodeString(test.in)
+               if err == nil {
+                       t.Errorf("#%d: expected error; got none")
+               } else if err.Error() != test.err {
+                       t.Errorf("#%d: got: %v want: %v", i, err, test.err)
                }
        }
 }
@@ -155,8 +112,8 @@ func TestDumper(t *testing.T) {
        }
 
        for stride := 1; stride < len(in); stride++ {
-               out := bytes.NewBuffer(nil)
-               dumper := Dumper(out)
+               var out bytes.Buffer
+               dumper := Dumper(&out)
                done := 0
                for done < len(in) {
                        todo := done + stride
index cc3103f032fb26c1c23cdfac08cbd7ca3c026eeb..775becfa7c9be2699e127a088f1cc3f5feeaefa6 100644 (file)
@@ -598,3 +598,24 @@ var pallValueIndent = `{
 }`
 
 var pallValueCompact = strings.Map(noSpace, pallValueIndent)
+
+func TestRefUnmarshal(t *testing.T) {
+       type S struct {
+               // Ref is defined in encode_test.go.
+               R0 Ref
+               R1 *Ref
+       }
+       want := S{
+               R0: 12,
+               R1: new(Ref),
+       }
+       *want.R1 = 12
+
+       var got S
+       if err := Unmarshal([]byte(`{"R0":"ref","R1":"ref"}`), &got); err != nil {
+               t.Fatalf("Unmarshal: %v", err)
+       }
+       if !reflect.DeepEqual(got, want) {
+               t.Errorf("got %+v, want %+v", got, want)
+       }
+}
index eac14a47ed7ac1722dfaf595c5ca0ecec0577892..83e73c09cb41c8d3bb80b5dae92e5c29a6487cb4 100644 (file)
@@ -262,8 +262,18 @@ func (e *encodeState) reflectValueQuoted(v reflect.Value, quoted bool) {
                return
        }
 
-       if j, ok := v.Interface().(Marshaler); ok && (v.Kind() != reflect.Ptr || !v.IsNil()) {
-               b, err := j.MarshalJSON()
+       m, ok := v.Interface().(Marshaler)
+       if !ok {
+               // T doesn't match the interface. Check against *T too.
+               if v.Kind() != reflect.Ptr && v.CanAddr() {
+                       m, ok = v.Addr().Interface().(Marshaler)
+                       if ok {
+                               v = v.Addr()
+                       }
+               }
+       }
+       if ok && (v.Kind() != reflect.Ptr || !v.IsNil()) {
+               b, err := m.MarshalJSON()
                if err == nil {
                        // copy JSON into buffer, checking validity.
                        err = Compact(&e.Buffer, b)
index 0e39559a463405ccbe164cd24794737dc2f37481..7a726a91c47bb47816e42e761de3944ebb4ca8ea 100644 (file)
@@ -126,3 +126,44 @@ func TestUnsupportedValues(t *testing.T) {
                }
        }
 }
+
+// Ref has Marshaler and Unmarshaler methods with pointer receiver.
+type Ref int
+
+func (*Ref) MarshalJSON() ([]byte, error) {
+       return []byte(`"ref"`), nil
+}
+
+func (r *Ref) UnmarshalJSON([]byte) error {
+       *r = 12
+       return nil
+}
+
+// Val has Marshaler methods with value receiver.
+type Val int
+
+func (Val) MarshalJSON() ([]byte, error) {
+       return []byte(`"val"`), nil
+}
+
+func TestRefValMarshal(t *testing.T) {
+       var s = struct {
+               R0 Ref
+               R1 *Ref
+               V0 Val
+               V1 *Val
+       }{
+               R0: 12,
+               R1: new(Ref),
+               V0: 13,
+               V1: new(Val),
+       }
+       const want = `{"R0":"ref","R1":"ref","V0":"val","V1":"val"}`
+       b, err := Marshal(&s)
+       if err != nil {
+               t.Fatalf("Marshal: %v", err)
+       }
+       if got := string(b); got != want {
+               t.Errorf("got %q, want %q", got, want)
+       }
+}
index 2661f410e015e138553a696a18360623e5697a83..054b6b3d564e1dbc7d96ee19276fd150f69c83a9 100644 (file)
@@ -185,18 +185,9 @@ func isSpace(c rune) bool {
        return c == ' ' || c == '\t' || c == '\r' || c == '\n'
 }
 
-// NOTE(rsc): The various instances of
-//
-//     if c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n')
-//
-// below should all be if c <= ' ' && isSpace(c), but inlining
-// the checks makes a significant difference (>10%) in tight loops
-// such as nextValue.  These should be rewritten with the clearer
-// function call once 6g knows to inline the call.
-
 // stateBeginValueOrEmpty is the state after reading `[`.
 func stateBeginValueOrEmpty(s *scanner, c int) int {
-       if c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
+       if c <= ' ' && isSpace(rune(c)) {
                return scanSkipSpace
        }
        if c == ']' {
@@ -207,7 +198,7 @@ func stateBeginValueOrEmpty(s *scanner, c int) int {
 
 // stateBeginValue is the state at the beginning of the input.
 func stateBeginValue(s *scanner, c int) int {
-       if c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
+       if c <= ' ' && isSpace(rune(c)) {
                return scanSkipSpace
        }
        switch c {
@@ -247,7 +238,7 @@ func stateBeginValue(s *scanner, c int) int {
 
 // stateBeginStringOrEmpty is the state after reading `{`.
 func stateBeginStringOrEmpty(s *scanner, c int) int {
-       if c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
+       if c <= ' ' && isSpace(rune(c)) {
                return scanSkipSpace
        }
        if c == '}' {
@@ -260,7 +251,7 @@ func stateBeginStringOrEmpty(s *scanner, c int) int {
 
 // stateBeginString is the state after reading `{"key": value,`.
 func stateBeginString(s *scanner, c int) int {
-       if c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
+       if c <= ' ' && isSpace(rune(c)) {
                return scanSkipSpace
        }
        if c == '"' {
@@ -280,7 +271,7 @@ func stateEndValue(s *scanner, c int) int {
                s.endTop = true
                return stateEndTop(s, c)
        }
-       if c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
+       if c <= ' ' && isSpace(rune(c)) {
                s.step = stateEndValue
                return scanSkipSpace
        }
index 3eb7c9fa0d91a9ee0a7bd872c1d73c4d5f00a4c6..38afbb42aff1ff1fa103d88b1a843f3c0eea47f3 100644 (file)
@@ -251,7 +251,7 @@ func Encode(out io.Writer, b *Block) (err error) {
 }
 
 func EncodeToMemory(b *Block) []byte {
-       buf := bytes.NewBuffer(nil)
-       Encode(buf, b)
+       var buf bytes.Buffer
+       Encode(&buf, b)
        return buf.Bytes()
 }
index 11efe55448709b7a6ee7bfe115a668984a906a35..9ae1578a501a30ce823163c0a318ed027c214c29 100644 (file)
@@ -73,7 +73,7 @@ var lineBreakerTests = []lineBreakerTest{
 
 func TestLineBreaker(t *testing.T) {
        for i, test := range lineBreakerTests {
-               buf := bytes.NewBuffer(nil)
+               buf := new(bytes.Buffer)
                var breaker lineBreaker
                breaker.out = buf
                _, err := breaker.Write([]byte(test.in))
@@ -93,7 +93,7 @@ func TestLineBreaker(t *testing.T) {
        }
 
        for i, test := range lineBreakerTests {
-               buf := bytes.NewBuffer(nil)
+               buf := new(bytes.Buffer)
                var breaker lineBreaker
                breaker.out = buf
 
index e0be33200864e9af9ffcc346963057f644fd0b6d..0f6c0f0795d7734467cfca0822612548181d180a 100644 (file)
@@ -532,6 +532,11 @@ var marshalTests = []struct {
                Value:     &NameInField{Name{Space: "ns", Local: "foo"}},
                ExpectXML: `<NameInField><foo xmlns="ns"></foo></NameInField>`,
        },
+       {
+               Value:         &NameInField{Name{Space: "ns", Local: "foo"}},
+               ExpectXML:     `<NameInField><foo xmlns="ns"><ignore></ignore></foo></NameInField>`,
+               UnmarshalOnly: true,
+       },
 
        // Marshaling zero xml.Name uses the tag or field name.
        {
index 871fe059cfa1880d0cf1790368b77048deb1bbff..bde875a012303ab840bbfb2ddc2d83eeb98b3c49 100644 (file)
@@ -265,12 +265,13 @@ func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
                saveData = v
 
        case reflect.Struct:
-               sv = v
-               typ := sv.Type()
+               typ := v.Type()
                if typ == nameType {
                        v.Set(reflect.ValueOf(start.Name))
                        break
                }
+
+               sv = v
                tinfo, err = getTypeInfo(typ)
                if err != nil {
                        return err
@@ -541,19 +542,21 @@ Loop:
        panic("unreachable")
 }
 
-// Have already read a start element.
-// Read tokens until we find the end element.
-// Token is taking care of making sure the
-// end element matches the start element we saw.
-func (p *Decoder) Skip() error {
+// Skip reads tokens until it has consumed the end element
+// matching the most recent start element already consumed.
+// It recurs if it encounters a start element, so it can be used to
+// skip nested structures.
+// It returns nil if it finds an end element matching the start
+// element; otherwise it returns an error describing the problem.
+func (d *Decoder) Skip() error {
        for {
-               tok, err := p.Token()
+               tok, err := d.Token()
                if err != nil {
                        return err
                }
                switch tok.(type) {
                case StartElement:
-                       if err := p.Skip(); err != nil {
+                       if err := d.Skip(); err != nil {
                                return err
                        }
                case EndElement:
index 2bf2c6b3032e98d580e7fabc62c6b6dc3f9db16d..5475f290d18dca4d439835523954bd3662a63215 100644 (file)
@@ -193,7 +193,7 @@ func structFieldInfo(typ reflect.Type, f *reflect.StructField) (*fieldInfo, erro
 
        // If the field type has an XMLName field, the names must match
        // so that the behavior of both marshalling and unmarshalling
-       // is straighforward and unambiguous.
+       // is straightforward and unambiguous.
        if finfo.flags&fElement != 0 {
                ftyp := f.Type
                xmlname := lookupXMLName(ftyp)
index f35976eea73012d27788d20e5bf837dab342814f..4bb22a4cb8098d4dc9f5f88be56df78902812912 100644 (file)
@@ -4,7 +4,7 @@
 
 /*
 
-Ebnflint verifies that EBNF productions are consistent and gramatically correct.
+Ebnflint verifies that EBNF productions are consistent and grammatically correct.
 It reads them from an HTML document such as the Go specification.
 
 Grammar productions are grouped in boxes demarcated by the HTML elements
@@ -13,7 +13,7 @@ Grammar productions are grouped in boxes demarcated by the HTML elements
 
 
 Usage:
-       ebnflint [--start production] [file]
+       go tool ebnflint [--start production] [file]
 
 The --start flag specifies the name of the start production for
 the grammar; it defaults to "Start".
index 2cb5aa6ed6c83115e387aadefc91d7ee2458db5e..d54fb229d03a5b15ad60ce3e5ff068ca621b6f96 100644 (file)
@@ -21,7 +21,7 @@ var fset = token.NewFileSet()
 var start = flag.String("start", "Start", "name of start production")
 
 func usage() {
-       fmt.Fprintf(os.Stderr, "usage: ebnflint [flags] [filename]\n")
+       fmt.Fprintf(os.Stderr, "usage: go tool ebnflint [flags] [filename]\n")
        flag.PrintDefaults()
        os.Exit(1)
 }
index 42be865ef080ad0b7c2a843da63dac852f40f25c..8f62a8c288079fb8110b73fe1cf9afa815e2d359 100644 (file)
@@ -233,8 +233,8 @@ func EscapeString(s string) string {
        if strings.IndexAny(s, escapedChars) == -1 {
                return s
        }
-       buf := bytes.NewBuffer(nil)
-       escape(buf, s)
+       var buf bytes.Buffer
+       escape(&buf, s)
        return buf.String()
 }
 
index 1528dffaafa1533304fdba8022b3db5f4b0aa648..f3f966cf58e73771f3811ab99ffe216669892c12 100644 (file)
@@ -159,9 +159,9 @@ func dump(n *Node) (string, error) {
        if n == nil || len(n.Child) == 0 {
                return "", nil
        }
-       b := bytes.NewBuffer(nil)
+       var b bytes.Buffer
        for _, child := range n.Child {
-               if err := dumpLevel(b, child, 0); err != nil {
+               if err := dumpLevel(&b, child, 0); err != nil {
                        return "", err
                }
        }
index 5a385a1b5c544df4fd762e0e6e7c926d4a825b4e..b5e9c2d6ea34c274effe074a8fbce9d113230019 100644 (file)
@@ -77,8 +77,7 @@ func (t Token) tagString() string {
        if len(t.Attr) == 0 {
                return t.Data
        }
-       buf := bytes.NewBuffer(nil)
-       buf.WriteString(t.Data)
+       buf := bytes.NewBufferString(t.Data)
        for _, a := range t.Attr {
                buf.WriteByte(' ')
                buf.WriteString(a.Key)
index 672d60c420940b558f85822013faa9b82d0e80ed..61d74006eab6154664dee216cf3759a07d5e4b71 100644 (file)
@@ -555,8 +555,8 @@ func TestUnescapeEscape(t *testing.T) {
 
 func TestBufAPI(t *testing.T) {
        s := "0<a>1</a>2<b>3<a>4<a>5</a>6</b>7</a>8<a/>9"
-       z := NewTokenizer(bytes.NewBuffer([]byte(s)))
-       result := bytes.NewBuffer(nil)
+       z := NewTokenizer(bytes.NewBufferString(s))
+       var result bytes.Buffer
        depth := 0
 loop:
        for {
index f12436618f299e7cc297712a2168b77f970855bd..912cf5db820c672e72888aba96db8cf134907ec8 100644 (file)
@@ -107,7 +107,11 @@ func (w *Watcher) AddWatch(path string, flags uint32) error {
        }
        wd, err := syscall.InotifyAddWatch(w.fd, path, flags)
        if err != nil {
-               return &os.PathError{"inotify_add_watch", path, err}
+               return &os.PathError{
+                       Op:   "inotify_add_watch",
+                       Path: path,
+                       Err:  err,
+               }
        }
 
        if !found {
index 7cad8a2ccd79abdd8fc4b0ca6c1d07f585d502db..5b48292cc3bc6e2cd8ec7cfcb9967e7c6eb2bbf7 100644 (file)
@@ -98,10 +98,10 @@ func (rb *reorderBuffer) insertOrdered(info runeInfo) bool {
 func (rb *reorderBuffer) insert(src input, i int, info runeInfo) bool {
        if info.size == 3 {
                if rune := src.hangul(i); rune != 0 {
-                       return rb.decomposeHangul(uint32(rune))
+                       return rb.decomposeHangul(rune)
                }
        }
-       if info.flags.hasDecomposition() {
+       if info.hasDecomposition() {
                dcomp := rb.f.decompose(src, i)
                rb.tmpBytes = inputBytes(dcomp)
                for i := 0; i < len(dcomp); {
@@ -126,26 +126,26 @@ func (rb *reorderBuffer) insert(src input, i int, info runeInfo) bool {
 }
 
 // appendRune inserts a rune at the end of the buffer. It is used for Hangul.
-func (rb *reorderBuffer) appendRune(r uint32) {
+func (rb *reorderBuffer) appendRune(r rune) {
        bn := rb.nbyte
        sz := utf8.EncodeRune(rb.byte[bn:], rune(r))
        rb.nbyte += utf8.UTFMax
-       rb.rune[rb.nrune] = runeInfo{bn, uint8(sz), 0, 0}
+       rb.rune[rb.nrune] = runeInfo{pos: bn, size: uint8(sz)}
        rb.nrune++
 }
 
 // assignRune sets a rune at position pos. It is used for Hangul and recomposition.
-func (rb *reorderBuffer) assignRune(pos int, r uint32) {
+func (rb *reorderBuffer) assignRune(pos int, r rune) {
        bn := rb.rune[pos].pos
        sz := utf8.EncodeRune(rb.byte[bn:], rune(r))
-       rb.rune[pos] = runeInfo{bn, uint8(sz), 0, 0}
+       rb.rune[pos] = runeInfo{pos: bn, size: uint8(sz)}
 }
 
 // runeAt returns the rune at position n. It is used for Hangul and recomposition.
-func (rb *reorderBuffer) runeAt(n int) uint32 {
+func (rb *reorderBuffer) runeAt(n int) rune {
        inf := rb.rune[n]
        r, _ := utf8.DecodeRune(rb.byte[inf.pos : inf.pos+inf.size])
-       return uint32(r)
+       return r
 }
 
 // bytesAt returns the UTF-8 encoding of the rune at position n.
@@ -237,7 +237,7 @@ func isHangulWithoutJamoT(b []byte) bool {
 // decomposeHangul algorithmically decomposes a Hangul rune into
 // its Jamo components.
 // See http://unicode.org/reports/tr15/#Hangul for details on decomposing Hangul.
-func (rb *reorderBuffer) decomposeHangul(r uint32) bool {
+func (rb *reorderBuffer) decomposeHangul(r rune) bool {
        b := rb.rune[:]
        n := rb.nrune
        if n+3 > len(b) {
@@ -319,7 +319,7 @@ func (rb *reorderBuffer) compose() {
                // get the info for the combined character. This is more
                // expensive than using the filter. Using combinesBackward()
                // is safe.
-               if ii.flags.combinesBackward() {
+               if ii.combinesBackward() {
                        cccB := b[k-1].ccc
                        cccC := ii.ccc
                        blocked := false // b[i] blocked by starter or greater or equal CCC?
index d06a00602f84fcbf6ddcf52baec96a9d07764da3..bf4443c991609283077ec7993a62c4ec70ddf1e6 100644 (file)
@@ -14,7 +14,6 @@ type runeInfo struct {
 }
 
 // functions dispatchable per form
-type boundaryFunc func(f *formInfo, info runeInfo) bool
 type lookupFunc func(b input, i int) runeInfo
 type decompFunc func(b input, i int) []byte
 
@@ -24,10 +23,8 @@ type formInfo struct {
 
        composing, compatibility bool // form type
 
-       decompose      decompFunc
-       info           lookupFunc
-       boundaryBefore boundaryFunc
-       boundaryAfter  boundaryFunc
+       decompose decompFunc
+       info      lookupFunc
 }
 
 var formTable []*formInfo
@@ -49,27 +46,17 @@ func init() {
                }
                if Form(i) == NFC || Form(i) == NFKC {
                        f.composing = true
-                       f.boundaryBefore = compBoundaryBefore
-                       f.boundaryAfter = compBoundaryAfter
-               } else {
-                       f.boundaryBefore = decompBoundary
-                       f.boundaryAfter = decompBoundary
                }
        }
 }
 
-func decompBoundary(f *formInfo, info runeInfo) bool {
-       if info.ccc == 0 && info.flags.isYesD() { // Implies isHangul(b) == true
-               return true
-       }
-       // We assume that the CCC of the first character in a decomposition
-       // is always non-zero if different from info.ccc and that we can return
-       // false at this point. This is verified by maketables.
-       return false
-}
-
-func compBoundaryBefore(f *formInfo, info runeInfo) bool {
-       if info.ccc == 0 && !info.flags.combinesBackward() {
+// We do not distinguish between boundaries for NFC, NFD, etc. to avoid
+// unexpected behavior for the user.  For example, in NFD, there is a boundary
+// after 'a'.  However, a might combine with modifiers, so from the application's
+// perspective it is not a good boundary. We will therefore always use the 
+// boundaries for the combining variants.
+func (i runeInfo) boundaryBefore() bool {
+       if i.ccc == 0 && !i.combinesBackward() {
                return true
        }
        // We assume that the CCC of the first character in a decomposition
@@ -78,15 +65,13 @@ func compBoundaryBefore(f *formInfo, info runeInfo) bool {
        return false
 }
 
-func compBoundaryAfter(f *formInfo, info runeInfo) bool {
-       // This misses values where the last char in a decomposition is a
-       // boundary such as Hangul with JamoT.
-       return info.isInert()
+func (i runeInfo) boundaryAfter() bool {
+       return i.isInert()
 }
 
 // We pack quick check data in 4 bits:
 //   0:    NFD_QC Yes (0) or No (1). No also means there is a decomposition.
-//   1..2: NFC_QC Yes(00), No (01), or Maybe (11)
+//   1..2: NFC_QC Yes(00), No (10), or Maybe (11)
 //   3:    Combines forward  (0 == false, 1 == true)
 // 
 // When all 4 bits are zero, the character is inert, meaning it is never
@@ -95,15 +80,12 @@ func compBoundaryAfter(f *formInfo, info runeInfo) bool {
 // We pack the bits for both NFC/D and NFKC/D in one byte.
 type qcInfo uint8
 
-func (i qcInfo) isYesC() bool  { return i&0x2 == 0 }
-func (i qcInfo) isNoC() bool   { return i&0x6 == 0x2 }
-func (i qcInfo) isMaybe() bool { return i&0x4 != 0 }
-func (i qcInfo) isYesD() bool  { return i&0x1 == 0 }
-func (i qcInfo) isNoD() bool   { return i&0x1 != 0 }
+func (i runeInfo) isYesC() bool { return i.flags&0x4 == 0 }
+func (i runeInfo) isYesD() bool { return i.flags&0x1 == 0 }
 
-func (i qcInfo) combinesForward() bool  { return i&0x8 != 0 }
-func (i qcInfo) combinesBackward() bool { return i&0x4 != 0 } // == isMaybe
-func (i qcInfo) hasDecomposition() bool { return i&0x1 != 0 } // == isNoD
+func (i runeInfo) combinesForward() bool  { return i.flags&0x8 != 0 }
+func (i runeInfo) combinesBackward() bool { return i.flags&0x2 != 0 } // == isMaybe
+func (i runeInfo) hasDecomposition() bool { return i.flags&0x1 != 0 } // == isNoD
 
 func (r runeInfo) isInert() bool {
        return r.flags&0xf == 0 && r.ccc == 0
@@ -111,7 +93,7 @@ func (r runeInfo) isInert() bool {
 
 // Wrappers for tables.go
 
-// The 16-bit value of the decompostion tries is an index into a byte
+// The 16-bit value of the decomposition tries is an index into a byte
 // array of UTF-8 decomposition sequences. The first byte is the number
 // of bytes in the decomposition (excluding this length byte). The actual
 // sequence starts at the offset+1.
@@ -137,7 +119,7 @@ func decomposeNFKC(s input, i int) []byte {
 // Note that the recomposition map for NFC and NFKC are identical.
 
 // combine returns the combined rune or 0 if it doesn't exist.
-func combine(a, b uint32) uint32 {
+func combine(a, b rune) rune {
        key := uint32(uint16(a))<<16 + uint32(uint16(b))
        return recompMap[key]
 }
@@ -148,10 +130,10 @@ func combine(a, b uint32) uint32 {
 //   12..15  qcInfo for NFKC/NFKD
 func lookupInfoNFC(b input, i int) runeInfo {
        v, sz := b.charinfo(i)
-       return runeInfo{0, uint8(sz), uint8(v), qcInfo(v >> 8)}
+       return runeInfo{size: uint8(sz), ccc: uint8(v), flags: qcInfo(v >> 8)}
 }
 
 func lookupInfoNFKC(b input, i int) runeInfo {
        v, sz := b.charinfo(i)
-       return runeInfo{0, uint8(sz), uint8(v), qcInfo(v >> 12)}
+       return runeInfo{size: uint8(sz), ccc: uint8(v), flags: qcInfo(v >> 12)}
 }
index 42e6f1b79471f8c590edc025e80fd8642f6d9d6f..7276c66cc123ff00525a721d7801c65ab999cc77 100644 (file)
@@ -14,7 +14,7 @@ type input interface {
        charinfo(p int) (uint16, int)
        decomposeNFC(p int) uint16
        decomposeNFKC(p int) uint16
-       hangul(p int) uint32
+       hangul(p int) rune
 }
 
 type inputString string
@@ -54,12 +54,12 @@ func (s inputString) decomposeNFKC(p int) uint16 {
        return nfkcDecompTrie.lookupStringUnsafe(string(s[p:]))
 }
 
-func (s inputString) hangul(p int) uint32 {
+func (s inputString) hangul(p int) rune {
        if !isHangulString(string(s[p:])) {
                return 0
        }
        rune, _ := utf8.DecodeRuneInString(string(s[p:]))
-       return uint32(rune)
+       return rune
 }
 
 type inputBytes []byte
@@ -96,10 +96,10 @@ func (s inputBytes) decomposeNFKC(p int) uint16 {
        return nfkcDecompTrie.lookupUnsafe(s[p:])
 }
 
-func (s inputBytes) hangul(p int) uint32 {
+func (s inputBytes) hangul(p int) rune {
        if !isHangul(s[p:]) {
                return 0
        }
        rune, _ := utf8.DecodeRune(s[p:])
-       return uint32(rune)
+       return rune
 }
index 9a97831716b473067fbfaab95876bd9822cc3d27..43e1429c1b1b1b415719b38ace2ca90ab3beb3ca 100644 (file)
@@ -562,7 +562,7 @@ func makeEntry(f *FormInfo) uint16 {
        switch f.quickCheck[MComposed] {
        case QCYes:
        case QCNo:
-               e |= 0x2
+               e |= 0x4
        case QCMaybe:
                e |= 0x6
        default:
@@ -718,7 +718,7 @@ func makeTables() {
                sz := nrentries * 8
                size += sz
                fmt.Printf("// recompMap: %d bytes (entries only)\n", sz)
-               fmt.Println("var recompMap = map[uint32]uint32{")
+               fmt.Println("var recompMap = map[uint32]rune{")
                for i, c := range chars {
                        f := c.forms[FCanonical]
                        d := f.decomp
index 3bd40470d5c351788b89368c8ccb6c3dbe916044..26bb4a0dc47b8de3bb74893840898ef5365db803 100644 (file)
@@ -188,11 +188,11 @@ func doAppend(rb *reorderBuffer, out []byte, p int) []byte {
                var info runeInfo
                if p < n {
                        info = fd.info(src, p)
-                       if p == 0 && !fd.boundaryBefore(fd, info) {
+                       if p == 0 && !info.boundaryBefore() {
                                out = decomposeToLastBoundary(rb, out)
                        }
                }
-               if info.size == 0 || fd.boundaryBefore(fd, info) {
+               if info.size == 0 || info.boundaryBefore() {
                        if fd.composing {
                                rb.compose()
                        }
@@ -257,11 +257,11 @@ func quickSpan(rb *reorderBuffer, i int) int {
                }
                cc := info.ccc
                if rb.f.composing {
-                       if !info.flags.isYesC() {
+                       if !info.isYesC() {
                                break
                        }
                } else {
-                       if !info.flags.isYesD() {
+                       if !info.isYesD() {
                                break
                        }
                }
@@ -316,13 +316,13 @@ func firstBoundary(rb *reorderBuffer) int {
        }
        fd := &rb.f
        info := fd.info(src, i)
-       for n := 0; info.size != 0 && !fd.boundaryBefore(fd, info); {
+       for n := 0; info.size != 0 && !info.boundaryBefore(); {
                i += int(info.size)
                if n++; n >= maxCombiningChars {
                        return i
                }
                if i >= nsrc {
-                       if !fd.boundaryAfter(fd, info) {
+                       if !info.boundaryAfter() {
                                return -1
                        }
                        return nsrc
@@ -368,11 +368,11 @@ func lastBoundary(fd *formInfo, b []byte) int {
        if p+int(info.size) != i { // trailing non-starter bytes: illegal UTF-8
                return i
        }
-       if fd.boundaryAfter(fd, info) {
+       if info.boundaryAfter() {
                return i
        }
        i = p
-       for n := 0; i >= 0 && !fd.boundaryBefore(fd, info); {
+       for n := 0; i >= 0 && !info.boundaryBefore(); {
                info, p = lastRuneStart(fd, b[:i])
                if n++; n >= maxCombiningChars {
                        return len(b)
@@ -404,7 +404,7 @@ func decomposeSegment(rb *reorderBuffer, sp int) int {
                        break
                }
                info = rb.f.info(rb.src, sp)
-               bound := rb.f.boundaryBefore(&rb.f, info)
+               bound := info.boundaryBefore()
                if bound || info.size == 0 {
                        break
                }
@@ -419,7 +419,7 @@ func lastRuneStart(fd *formInfo, buf []byte) (runeInfo, int) {
        for ; p >= 0 && !utf8.RuneStart(buf[p]); p-- {
        }
        if p < 0 {
-               return runeInfo{0, 0, 0, 0}, -1
+               return runeInfo{}, -1
        }
        return fd.info(inputBytes(buf), p), p
 }
@@ -433,7 +433,7 @@ func decomposeToLastBoundary(rb *reorderBuffer, buf []byte) []byte {
                // illegal trailing continuation bytes
                return buf
        }
-       if rb.f.boundaryAfter(fd, info) {
+       if info.boundaryAfter() {
                return buf
        }
        var add [maxBackRunes]runeInfo // stores runeInfo in reverse order
@@ -441,13 +441,13 @@ func decomposeToLastBoundary(rb *reorderBuffer, buf []byte) []byte {
        padd := 1
        n := 1
        p := len(buf) - int(info.size)
-       for ; p >= 0 && !rb.f.boundaryBefore(fd, info); p -= int(info.size) {
+       for ; p >= 0 && !info.boundaryBefore(); p -= int(info.size) {
                info, i = lastRuneStart(fd, buf[:p])
                if int(info.size) != p-i {
                        break
                }
                // Check that decomposition doesn't result in overflow.
-               if info.flags.hasDecomposition() {
+               if info.hasDecomposition() {
                        dcomp := rb.f.decompose(inputBytes(buf), p-int(info.size))
                        for i := 0; i < len(dcomp); {
                                inf := rb.f.info(inputBytes(dcomp), i)
index 2e0c1f17120e7f11a473069362603ee734044feb..c7d5e08fca0a6321d7155a8f9fa057c39655d91a 100644 (file)
@@ -495,11 +495,11 @@ func TestAppend(t *testing.T) {
        runAppendTests(t, "TestString", NFKC, stringF, appendTests)
 }
 
-func doFormBenchmark(b *testing.B, f Form, s string) {
+func doFormBenchmark(b *testing.B, inf, f Form, s string) {
        b.StopTimer()
-       in := []byte(s)
+       in := inf.Bytes([]byte(s))
        buf := make([]byte, 2*len(in))
-       b.SetBytes(int64(len(s)))
+       b.SetBytes(int64(len(in)))
        b.StartTimer()
        for i := 0; i < b.N; i++ {
                buf = f.Append(buf[0:0], in...)
@@ -510,16 +510,43 @@ func doFormBenchmark(b *testing.B, f Form, s string) {
 var ascii = strings.Repeat("There is nothing to change here! ", 500)
 
 func BenchmarkNormalizeAsciiNFC(b *testing.B) {
-       doFormBenchmark(b, NFC, ascii)
+       doFormBenchmark(b, NFC, NFC, ascii)
 }
 func BenchmarkNormalizeAsciiNFD(b *testing.B) {
-       doFormBenchmark(b, NFD, ascii)
+       doFormBenchmark(b, NFC, NFD, ascii)
 }
 func BenchmarkNormalizeAsciiNFKC(b *testing.B) {
-       doFormBenchmark(b, NFKC, ascii)
+       doFormBenchmark(b, NFC, NFKC, ascii)
 }
 func BenchmarkNormalizeAsciiNFKD(b *testing.B) {
-       doFormBenchmark(b, NFKD, ascii)
+       doFormBenchmark(b, NFC, NFKD, ascii)
+}
+
+func BenchmarkNormalizeNFC2NFC(b *testing.B) {
+       doFormBenchmark(b, NFC, NFC, txt_all)
+}
+func BenchmarkNormalizeNFC2NFD(b *testing.B) {
+       doFormBenchmark(b, NFC, NFD, txt_all)
+}
+func BenchmarkNormalizeNFD2NFC(b *testing.B) {
+       doFormBenchmark(b, NFD, NFC, txt_all)
+}
+func BenchmarkNormalizeNFD2NFD(b *testing.B) {
+       doFormBenchmark(b, NFD, NFD, txt_all)
+}
+
+// Hangul is often special-cased, so we test it separately.
+func BenchmarkNormalizeHangulNFC2NFC(b *testing.B) {
+       doFormBenchmark(b, NFC, NFC, txt_kr)
+}
+func BenchmarkNormalizeHangulNFC2NFD(b *testing.B) {
+       doFormBenchmark(b, NFC, NFD, txt_kr)
+}
+func BenchmarkNormalizeHangulNFD2NFC(b *testing.B) {
+       doFormBenchmark(b, NFD, NFC, txt_kr)
+}
+func BenchmarkNormalizeHangulNFD2NFD(b *testing.B) {
+       doFormBenchmark(b, NFD, NFD, txt_kr)
 }
 
 func doTextBenchmark(b *testing.B, s string) {
@@ -657,3 +684,6 @@ const txt_cn = `您可以自由: 复制、发行、展览、表演、放映、
 署名 — 您必须按照作者或者许可人指定的方式对作品进行署名。
 相同方式共享 — 如果您改变、转换本作品或者以本作品为基础进行创作,
 您只能采用与本协议相同的许可协议发布基于本作品的演绎作品。`
+
+const txt_cjk = txt_cn + txt_jp + txt_kr
+const txt_all = txt_vn + twoByteUtf8 + threeByteUtf8 + txt_cjk
index 9044a72fd476ffd31caad9e6372c29639f867ca7..02a481b3b3d29149a44093b6a4d4fd6adf35dfd6 100644 (file)
@@ -4661,7 +4661,7 @@ var nfkcDecompLookup = [960]uint8{
 var nfkcDecompTrie = trie{nfkcDecompLookup[:], nfkcDecompValues[:], nfkcDecompSparseValues[:], nfkcDecompSparseOffset[:], 66}
 
 // recompMap: 7448 bytes (entries only)
-var recompMap = map[uint32]uint32{
+var recompMap = map[uint32]rune{
        0x00410300: 0x00C0,
        0x00410301: 0x00C1,
        0x00410302: 0x00C2,
@@ -5637,7 +5637,7 @@ var charInfoValues = [1024]uint16{
        0x0136: 0x0001, 0x0137: 0x0001, 0x0138: 0x6601, 0x0139: 0x00dc, 0x013a: 0x00dc, 0x013b: 0x00dc,
        0x013c: 0x00dc, 0x013d: 0x00e6, 0x013e: 0x00e6, 0x013f: 0x00e6,
        // Block 0x5, offset 0x140
-       0x0140: 0x33e6, 0x0141: 0x33e6, 0x0142: 0x66e6, 0x0143: 0x33e6, 0x0144: 0x33e6, 0x0145: 0x66f0,
+       0x0140: 0x55e6, 0x0141: 0x55e6, 0x0142: 0x66e6, 0x0143: 0x55e6, 0x0144: 0x55e6, 0x0145: 0x66f0,
        0x0146: 0x00e6, 0x0147: 0x00dc, 0x0148: 0x00dc, 0x0149: 0x00dc, 0x014a: 0x00e6, 0x014b: 0x00e6,
        0x014c: 0x00e6, 0x014d: 0x00dc, 0x014e: 0x00dc, 0x0150: 0x00e6, 0x0151: 0x00e6,
        0x0152: 0x00e6, 0x0153: 0x00dc, 0x0154: 0x00dc, 0x0155: 0x00dc, 0x0156: 0x00dc, 0x0157: 0x00e6,
@@ -5645,12 +5645,12 @@ var charInfoValues = [1024]uint16{
        0x015e: 0x00ea, 0x015f: 0x00e9, 0x0160: 0x00ea, 0x0161: 0x00ea, 0x0162: 0x00e9, 0x0163: 0x00e6,
        0x0164: 0x00e6, 0x0165: 0x00e6, 0x0166: 0x00e6, 0x0167: 0x00e6, 0x0168: 0x00e6, 0x0169: 0x00e6,
        0x016a: 0x00e6, 0x016b: 0x00e6, 0x016c: 0x00e6, 0x016d: 0x00e6, 0x016e: 0x00e6, 0x016f: 0x00e6,
-       0x0174: 0x3300,
-       0x017a: 0x3000,
-       0x017e: 0x3300,
+       0x0174: 0x5500,
+       0x017a: 0x5000,
+       0x017e: 0x5500,
        // Block 0x6, offset 0x180
-       0x0184: 0x3000, 0x0185: 0x3100,
-       0x0186: 0x1100, 0x0187: 0x3300, 0x0188: 0x1100, 0x0189: 0x1100, 0x018a: 0x1100,
+       0x0184: 0x5000, 0x0185: 0x5100,
+       0x0186: 0x1100, 0x0187: 0x5500, 0x0188: 0x1100, 0x0189: 0x1100, 0x018a: 0x1100,
        0x018c: 0x1100, 0x018e: 0x1100, 0x018f: 0x1100, 0x0190: 0x1100, 0x0191: 0x8800,
        0x0195: 0x8800, 0x0197: 0x8800,
        0x0199: 0x8800,
@@ -5673,7 +5673,7 @@ var charInfoValues = [1024]uint16{
        0x01f6: 0x8800, 0x01f7: 0x8800, 0x01f8: 0x8800, 0x01f9: 0x1100, 0x01fa: 0x8800,
        0x01fe: 0x8800,
        // Block 0x8, offset 0x200
-       0x0207: 0x3000,
+       0x0207: 0x5000,
        0x0211: 0x00dc,
        0x0212: 0x00e6, 0x0213: 0x00e6, 0x0214: 0x00e6, 0x0215: 0x00e6, 0x0216: 0x00dc, 0x0217: 0x00e6,
        0x0218: 0x00e6, 0x0219: 0x00e6, 0x021a: 0x00de, 0x021b: 0x00dc, 0x021c: 0x00e6, 0x021d: 0x00e6,
@@ -5689,8 +5689,8 @@ var charInfoValues = [1024]uint16{
        0x0252: 0x0022, 0x0253: 0x66e6, 0x0254: 0x66e6, 0x0255: 0x66dc, 0x0256: 0x00dc, 0x0257: 0x00e6,
        0x0258: 0x00e6, 0x0259: 0x00e6, 0x025a: 0x00e6, 0x025b: 0x00e6, 0x025c: 0x00dc, 0x025d: 0x00e6,
        0x025e: 0x00e6, 0x025f: 0x00dc,
-       0x0270: 0x0023, 0x0275: 0x3000,
-       0x0276: 0x3000, 0x0277: 0x3000, 0x0278: 0x3000,
+       0x0270: 0x0023, 0x0275: 0x5000,
+       0x0276: 0x5000, 0x0277: 0x5000, 0x0278: 0x5000,
        // Block 0xa, offset 0x280
        0x0280: 0x9900, 0x0281: 0x9900, 0x0282: 0x1100, 0x0283: 0x1100, 0x0284: 0x1100, 0x0285: 0x1100,
        0x0288: 0x9900, 0x0289: 0x9900, 0x028a: 0x1100, 0x028b: 0x1100,
@@ -5700,21 +5700,21 @@ var charInfoValues = [1024]uint16{
        0x029f: 0x1100, 0x02a0: 0x9900, 0x02a1: 0x9900, 0x02a2: 0x9900, 0x02a3: 0x9900,
        0x02a4: 0x9900, 0x02a5: 0x9900, 0x02a6: 0x9900, 0x02a7: 0x9900, 0x02a8: 0x9900, 0x02a9: 0x9900,
        0x02aa: 0x9900, 0x02ab: 0x9900, 0x02ac: 0x9900, 0x02ad: 0x9900, 0x02ae: 0x9900, 0x02af: 0x9900,
-       0x02b0: 0x9900, 0x02b1: 0x3300, 0x02b2: 0x1100, 0x02b3: 0x3300, 0x02b4: 0x9900, 0x02b5: 0x3300,
-       0x02b6: 0x1100, 0x02b7: 0x3300, 0x02b8: 0x1100, 0x02b9: 0x3300, 0x02ba: 0x1100, 0x02bb: 0x3300,
-       0x02bc: 0x9900, 0x02bd: 0x3300,
+       0x02b0: 0x9900, 0x02b1: 0x5500, 0x02b2: 0x1100, 0x02b3: 0x5500, 0x02b4: 0x9900, 0x02b5: 0x5500,
+       0x02b6: 0x1100, 0x02b7: 0x5500, 0x02b8: 0x1100, 0x02b9: 0x5500, 0x02ba: 0x1100, 0x02bb: 0x5500,
+       0x02bc: 0x9900, 0x02bd: 0x5500,
        // Block 0xb, offset 0x2c0
-       0x02c0: 0x3000, 0x02c1: 0x3100, 0x02c2: 0x1100, 0x02c3: 0x1100, 0x02c4: 0x1100,
-       0x02c6: 0x9900, 0x02c7: 0x1100, 0x02c8: 0x1100, 0x02c9: 0x3300, 0x02ca: 0x1100, 0x02cb: 0x3300,
-       0x02cc: 0x1100, 0x02cd: 0x3100, 0x02ce: 0x3100, 0x02cf: 0x3100, 0x02d0: 0x1100, 0x02d1: 0x1100,
-       0x02d2: 0x1100, 0x02d3: 0x3300, 0x02d6: 0x1100, 0x02d7: 0x1100,
-       0x02d8: 0x1100, 0x02d9: 0x1100, 0x02da: 0x1100, 0x02db: 0x3300, 0x02dd: 0x3100,
-       0x02de: 0x3100, 0x02df: 0x3100, 0x02e0: 0x1100, 0x02e1: 0x1100, 0x02e2: 0x1100, 0x02e3: 0x3300,
+       0x02c0: 0x5000, 0x02c1: 0x5100, 0x02c2: 0x1100, 0x02c3: 0x1100, 0x02c4: 0x1100,
+       0x02c6: 0x9900, 0x02c7: 0x1100, 0x02c8: 0x1100, 0x02c9: 0x5500, 0x02ca: 0x1100, 0x02cb: 0x5500,
+       0x02cc: 0x1100, 0x02cd: 0x5100, 0x02ce: 0x5100, 0x02cf: 0x5100, 0x02d0: 0x1100, 0x02d1: 0x1100,
+       0x02d2: 0x1100, 0x02d3: 0x5500, 0x02d6: 0x1100, 0x02d7: 0x1100,
+       0x02d8: 0x1100, 0x02d9: 0x1100, 0x02da: 0x1100, 0x02db: 0x5500, 0x02dd: 0x5100,
+       0x02de: 0x5100, 0x02df: 0x5100, 0x02e0: 0x1100, 0x02e1: 0x1100, 0x02e2: 0x1100, 0x02e3: 0x5500,
        0x02e4: 0x1100, 0x02e5: 0x1100, 0x02e6: 0x1100, 0x02e7: 0x1100, 0x02e8: 0x1100, 0x02e9: 0x1100,
-       0x02ea: 0x1100, 0x02eb: 0x3300, 0x02ec: 0x1100, 0x02ed: 0x3100, 0x02ee: 0x3300, 0x02ef: 0x3300,
+       0x02ea: 0x1100, 0x02eb: 0x5500, 0x02ec: 0x1100, 0x02ed: 0x5100, 0x02ee: 0x5500, 0x02ef: 0x5500,
        0x02f2: 0x1100, 0x02f3: 0x1100, 0x02f4: 0x1100,
-       0x02f6: 0x9900, 0x02f7: 0x1100, 0x02f8: 0x1100, 0x02f9: 0x3300, 0x02fa: 0x1100, 0x02fb: 0x3300,
-       0x02fc: 0x1100, 0x02fd: 0x3300, 0x02fe: 0x3800,
+       0x02f6: 0x9900, 0x02f7: 0x1100, 0x02f8: 0x1100, 0x02f9: 0x5500, 0x02fa: 0x1100, 0x02fb: 0x5500,
+       0x02fc: 0x1100, 0x02fd: 0x5500, 0x02fe: 0x5800,
        // Block 0xc, offset 0x300
        0x0301: 0x1100, 0x0303: 0x8800, 0x0304: 0x1100, 0x0305: 0x8800,
        0x0307: 0x1100, 0x0308: 0x8800, 0x0309: 0x1100,
@@ -5738,8 +5738,8 @@ var charInfoValues = [1024]uint16{
        0x037c: 0x1100, 0x037d: 0x1100,
        // Block 0xe, offset 0x380
        0x0394: 0x1100,
-       0x0399: 0x6608, 0x039a: 0x6608, 0x039b: 0x3000, 0x039c: 0x3000, 0x039d: 0x8800,
-       0x039e: 0x1100, 0x039f: 0x3000,
+       0x0399: 0x6608, 0x039a: 0x6608, 0x039b: 0x5000, 0x039c: 0x5000, 0x039d: 0x8800,
+       0x039e: 0x1100, 0x039f: 0x5000,
        0x03a6: 0x8800,
        0x03ab: 0x8800, 0x03ac: 0x1100, 0x03ad: 0x8800, 0x03ae: 0x1100, 0x03af: 0x8800,
        0x03b0: 0x1100, 0x03b1: 0x8800, 0x03b2: 0x1100, 0x03b3: 0x8800, 0x03b4: 0x1100, 0x03b5: 0x8800,
@@ -5754,7 +5754,7 @@ var charInfoValues = [1024]uint16{
        0x03ef: 0x8800,
        0x03f0: 0x8800, 0x03f1: 0x8800, 0x03f2: 0x8800, 0x03f4: 0x1100,
        0x03f7: 0x1100, 0x03f8: 0x1100, 0x03f9: 0x1100, 0x03fa: 0x1100,
-       0x03fd: 0x8800, 0x03fe: 0x1100, 0x03ff: 0x3000,
+       0x03fd: 0x8800, 0x03fe: 0x1100, 0x03ff: 0x5000,
 }
 
 // charInfoSparseOffset: 156 entries, 312 bytes
@@ -5764,13 +5764,13 @@ var charInfoSparseOffset = []uint16{0x0, 0x8, 0x13, 0x21, 0x25, 0x2f, 0x36, 0x39
 var charInfoSparseValues = [757]valueRange{
        // Block 0x0, offset 0x1
        {value: 0x0000, lo: 0x07},
-       {value: 0x3000, lo: 0xa0, hi: 0xa0},
-       {value: 0x3800, lo: 0xa8, hi: 0xa8},
-       {value: 0x3000, lo: 0xaa, hi: 0xaa},
-       {value: 0x3000, lo: 0xaf, hi: 0xaf},
-       {value: 0x3000, lo: 0xb2, hi: 0xb5},
-       {value: 0x3000, lo: 0xb8, hi: 0xba},
-       {value: 0x3000, lo: 0xbc, hi: 0xbe},
+       {value: 0x5000, lo: 0xa0, hi: 0xa0},
+       {value: 0x5800, lo: 0xa8, hi: 0xa8},
+       {value: 0x5000, lo: 0xaa, hi: 0xaa},
+       {value: 0x5000, lo: 0xaf, hi: 0xaf},
+       {value: 0x5000, lo: 0xb2, hi: 0xb5},
+       {value: 0x5000, lo: 0xb8, hi: 0xba},
+       {value: 0x5000, lo: 0xbc, hi: 0xbe},
        // Block 0x1, offset 0x2
        {value: 0x0000, lo: 0x0a},
        {value: 0x1100, lo: 0x80, hi: 0x81},
@@ -5779,15 +5779,15 @@ var charInfoSparseValues = [757]valueRange{
        {value: 0x9900, lo: 0x92, hi: 0x93},
        {value: 0x1100, lo: 0x94, hi: 0xa5},
        {value: 0x1100, lo: 0xa8, hi: 0xb0},
-       {value: 0x3000, lo: 0xb2, hi: 0xb3},
+       {value: 0x5000, lo: 0xb2, hi: 0xb3},
        {value: 0x1100, lo: 0xb4, hi: 0xb7},
        {value: 0x1100, lo: 0xb9, hi: 0xbe},
-       {value: 0x3000, lo: 0xbf, hi: 0xbf},
+       {value: 0x5000, lo: 0xbf, hi: 0xbf},
        // Block 0x2, offset 0x3
        {value: 0x0000, lo: 0x0d},
-       {value: 0x3000, lo: 0x80, hi: 0x80},
+       {value: 0x5000, lo: 0x80, hi: 0x80},
        {value: 0x1100, lo: 0x83, hi: 0x88},
-       {value: 0x3000, lo: 0x89, hi: 0x89},
+       {value: 0x5000, lo: 0x89, hi: 0x89},
        {value: 0x9900, lo: 0x8c, hi: 0x8d},
        {value: 0x1100, lo: 0x8e, hi: 0x91},
        {value: 0x1100, lo: 0x94, hi: 0x99},
@@ -5797,7 +5797,7 @@ var charInfoSparseValues = [757]valueRange{
        {value: 0x1100, lo: 0xa2, hi: 0xa5},
        {value: 0x9900, lo: 0xa8, hi: 0xab},
        {value: 0x1100, lo: 0xac, hi: 0xbe},
-       {value: 0x3800, lo: 0xbf, hi: 0xbf},
+       {value: 0x5800, lo: 0xbf, hi: 0xbf},
        // Block 0x3, offset 0x4
        {value: 0x0000, lo: 0x03},
        {value: 0x9900, lo: 0xa0, hi: 0xa1},
@@ -5805,13 +5805,13 @@ var charInfoSparseValues = [757]valueRange{
        {value: 0x8800, lo: 0xb7, hi: 0xb7},
        // Block 0x4, offset 0x5
        {value: 0x0000, lo: 0x09},
-       {value: 0x3000, lo: 0x84, hi: 0x8c},
+       {value: 0x5000, lo: 0x84, hi: 0x8c},
        {value: 0x1100, lo: 0x8d, hi: 0x9c},
        {value: 0x1100, lo: 0x9e, hi: 0xa3},
        {value: 0x1100, lo: 0xa6, hi: 0xa9},
        {value: 0x9900, lo: 0xaa, hi: 0xab},
        {value: 0x1100, lo: 0xac, hi: 0xb0},
-       {value: 0x3000, lo: 0xb1, hi: 0xb3},
+       {value: 0x5000, lo: 0xb1, hi: 0xb3},
        {value: 0x1100, lo: 0xb4, hi: 0xb5},
        {value: 0x1100, lo: 0xb8, hi: 0xbf},
        // Block 0x5, offset 0x6
@@ -5825,11 +5825,11 @@ var charInfoSparseValues = [757]valueRange{
        // Block 0x6, offset 0x7
        {value: 0x0000, lo: 0x02},
        {value: 0x8800, lo: 0x92, hi: 0x92},
-       {value: 0x3000, lo: 0xb0, hi: 0xb8},
+       {value: 0x5000, lo: 0xb0, hi: 0xb8},
        // Block 0x7, offset 0x8
        {value: 0x0000, lo: 0x02},
-       {value: 0x3000, lo: 0x98, hi: 0x9d},
-       {value: 0x3000, lo: 0xa0, hi: 0xa4},
+       {value: 0x5000, lo: 0x98, hi: 0x9d},
+       {value: 0x5000, lo: 0xa0, hi: 0xa4},
        // Block 0x8, offset 0x9
        {value: 0x0000, lo: 0x0d},
        {value: 0x8800, lo: 0x81, hi: 0x81},
@@ -5838,13 +5838,13 @@ var charInfoSparseValues = [757]valueRange{
        {value: 0x9900, lo: 0x8a, hi: 0x8b},
        {value: 0x1100, lo: 0x8c, hi: 0x8d},
        {value: 0x9900, lo: 0x8e, hi: 0x8e},
-       {value: 0x3000, lo: 0x90, hi: 0x91},
-       {value: 0x3800, lo: 0x92, hi: 0x92},
-       {value: 0x3100, lo: 0x93, hi: 0x94},
-       {value: 0x3000, lo: 0x95, hi: 0x96},
-       {value: 0x3000, lo: 0xb0, hi: 0xb2},
-       {value: 0x3000, lo: 0xb4, hi: 0xb5},
-       {value: 0x3000, lo: 0xb9, hi: 0xb9},
+       {value: 0x5000, lo: 0x90, hi: 0x91},
+       {value: 0x5800, lo: 0x92, hi: 0x92},
+       {value: 0x5100, lo: 0x93, hi: 0x94},
+       {value: 0x5000, lo: 0x95, hi: 0x96},
+       {value: 0x5000, lo: 0xb0, hi: 0xb2},
+       {value: 0x5000, lo: 0xb4, hi: 0xb5},
+       {value: 0x5000, lo: 0xb9, hi: 0xb9},
        // Block 0x9, offset 0xa
        {value: 0x0000, lo: 0x0b},
        {value: 0x8800, lo: 0x83, hi: 0x83},
@@ -5954,7 +5954,7 @@ var charInfoSparseValues = [757]valueRange{
        {value: 0x00e6, lo: 0x91, hi: 0x91},
        {value: 0x00dc, lo: 0x92, hi: 0x92},
        {value: 0x00e6, lo: 0x93, hi: 0x94},
-       {value: 0x3300, lo: 0x98, hi: 0x9f},
+       {value: 0x5500, lo: 0x98, hi: 0x9f},
        // Block 0x16, offset 0x17
        {value: 0x0000, lo: 0x02},
        {value: 0x0007, lo: 0xbc, hi: 0xbc},
@@ -5965,18 +5965,18 @@ var charInfoSparseValues = [757]valueRange{
        {value: 0x1100, lo: 0x8b, hi: 0x8c},
        {value: 0x0009, lo: 0x8d, hi: 0x8d},
        {value: 0x6600, lo: 0x97, hi: 0x97},
-       {value: 0x3300, lo: 0x9c, hi: 0x9d},
-       {value: 0x3300, lo: 0x9f, hi: 0x9f},
+       {value: 0x5500, lo: 0x9c, hi: 0x9d},
+       {value: 0x5500, lo: 0x9f, hi: 0x9f},
        // Block 0x18, offset 0x19
        {value: 0x0000, lo: 0x03},
-       {value: 0x3300, lo: 0xb3, hi: 0xb3},
-       {value: 0x3300, lo: 0xb6, hi: 0xb6},
+       {value: 0x5500, lo: 0xb3, hi: 0xb3},
+       {value: 0x5500, lo: 0xb6, hi: 0xb6},
        {value: 0x0007, lo: 0xbc, hi: 0xbc},
        // Block 0x19, offset 0x1a
        {value: 0x0000, lo: 0x03},
        {value: 0x0009, lo: 0x8d, hi: 0x8d},
-       {value: 0x3300, lo: 0x99, hi: 0x9b},
-       {value: 0x3300, lo: 0x9e, hi: 0x9e},
+       {value: 0x5500, lo: 0x99, hi: 0x9b},
+       {value: 0x5500, lo: 0x9e, hi: 0x9e},
        // Block 0x1a, offset 0x1b
        {value: 0x0000, lo: 0x01},
        {value: 0x0007, lo: 0xbc, hi: 0xbc},
@@ -5990,7 +5990,7 @@ var charInfoSparseValues = [757]valueRange{
        {value: 0x1100, lo: 0x8b, hi: 0x8c},
        {value: 0x0009, lo: 0x8d, hi: 0x8d},
        {value: 0x6600, lo: 0x96, hi: 0x97},
-       {value: 0x3300, lo: 0x9c, hi: 0x9d},
+       {value: 0x5500, lo: 0x9c, hi: 0x9d},
        // Block 0x1d, offset 0x1e
        {value: 0x0000, lo: 0x03},
        {value: 0x8800, lo: 0x92, hi: 0x92},
@@ -6036,7 +6036,7 @@ var charInfoSparseValues = [757]valueRange{
        {value: 0x6600, lo: 0x9f, hi: 0x9f},
        // Block 0x24, offset 0x25
        {value: 0x0000, lo: 0x03},
-       {value: 0x3000, lo: 0xb3, hi: 0xb3},
+       {value: 0x5000, lo: 0xb3, hi: 0xb3},
        {value: 0x0067, lo: 0xb8, hi: 0xb9},
        {value: 0x0009, lo: 0xba, hi: 0xba},
        // Block 0x25, offset 0x26
@@ -6044,49 +6044,49 @@ var charInfoSparseValues = [757]valueRange{
        {value: 0x006b, lo: 0x88, hi: 0x8b},
        // Block 0x26, offset 0x27
        {value: 0x0000, lo: 0x02},
-       {value: 0x3000, lo: 0xb3, hi: 0xb3},
+       {value: 0x5000, lo: 0xb3, hi: 0xb3},
        {value: 0x0076, lo: 0xb8, hi: 0xb9},
        // Block 0x27, offset 0x28
        {value: 0x0000, lo: 0x02},
        {value: 0x007a, lo: 0x88, hi: 0x8b},
-       {value: 0x3000, lo: 0x9c, hi: 0x9d},
+       {value: 0x5000, lo: 0x9c, hi: 0x9d},
        // Block 0x28, offset 0x29
        {value: 0x0000, lo: 0x05},
-       {value: 0x3000, lo: 0x8c, hi: 0x8c},
+       {value: 0x5000, lo: 0x8c, hi: 0x8c},
        {value: 0x00dc, lo: 0x98, hi: 0x99},
        {value: 0x00dc, lo: 0xb5, hi: 0xb5},
        {value: 0x00dc, lo: 0xb7, hi: 0xb7},
        {value: 0x00d8, lo: 0xb9, hi: 0xb9},
        // Block 0x29, offset 0x2a
        {value: 0x0000, lo: 0x0f},
-       {value: 0x3300, lo: 0x83, hi: 0x83},
-       {value: 0x3300, lo: 0x8d, hi: 0x8d},
-       {value: 0x3300, lo: 0x92, hi: 0x92},
-       {value: 0x3300, lo: 0x97, hi: 0x97},
-       {value: 0x3300, lo: 0x9c, hi: 0x9c},
-       {value: 0x3300, lo: 0xa9, hi: 0xa9},
+       {value: 0x5500, lo: 0x83, hi: 0x83},
+       {value: 0x5500, lo: 0x8d, hi: 0x8d},
+       {value: 0x5500, lo: 0x92, hi: 0x92},
+       {value: 0x5500, lo: 0x97, hi: 0x97},
+       {value: 0x5500, lo: 0x9c, hi: 0x9c},
+       {value: 0x5500, lo: 0xa9, hi: 0xa9},
        {value: 0x0081, lo: 0xb1, hi: 0xb1},
        {value: 0x0082, lo: 0xb2, hi: 0xb2},
-       {value: 0x3300, lo: 0xb3, hi: 0xb3},
+       {value: 0x5500, lo: 0xb3, hi: 0xb3},
        {value: 0x0084, lo: 0xb4, hi: 0xb4},
-       {value: 0x3300, lo: 0xb5, hi: 0xb6},
-       {value: 0x3000, lo: 0xb7, hi: 0xb7},
-       {value: 0x3300, lo: 0xb8, hi: 0xb8},
-       {value: 0x3000, lo: 0xb9, hi: 0xb9},
+       {value: 0x5500, lo: 0xb5, hi: 0xb6},
+       {value: 0x5000, lo: 0xb7, hi: 0xb7},
+       {value: 0x5500, lo: 0xb8, hi: 0xb8},
+       {value: 0x5000, lo: 0xb9, hi: 0xb9},
        {value: 0x0082, lo: 0xba, hi: 0xbd},
        // Block 0x2a, offset 0x2b
        {value: 0x0000, lo: 0x0b},
        {value: 0x0082, lo: 0x80, hi: 0x80},
-       {value: 0x3300, lo: 0x81, hi: 0x81},
+       {value: 0x5500, lo: 0x81, hi: 0x81},
        {value: 0x00e6, lo: 0x82, hi: 0x83},
        {value: 0x0009, lo: 0x84, hi: 0x84},
        {value: 0x00e6, lo: 0x86, hi: 0x87},
-       {value: 0x3300, lo: 0x93, hi: 0x93},
-       {value: 0x3300, lo: 0x9d, hi: 0x9d},
-       {value: 0x3300, lo: 0xa2, hi: 0xa2},
-       {value: 0x3300, lo: 0xa7, hi: 0xa7},
-       {value: 0x3300, lo: 0xac, hi: 0xac},
-       {value: 0x3300, lo: 0xb9, hi: 0xb9},
+       {value: 0x5500, lo: 0x93, hi: 0x93},
+       {value: 0x5500, lo: 0x9d, hi: 0x9d},
+       {value: 0x5500, lo: 0xa2, hi: 0xa2},
+       {value: 0x5500, lo: 0xa7, hi: 0xa7},
+       {value: 0x5500, lo: 0xac, hi: 0xac},
+       {value: 0x5500, lo: 0xb9, hi: 0xb9},
        // Block 0x2b, offset 0x2c
        {value: 0x0000, lo: 0x01},
        {value: 0x00dc, lo: 0x86, hi: 0x86},
@@ -6102,7 +6102,7 @@ var charInfoSparseValues = [757]valueRange{
        {value: 0x00dc, lo: 0x8d, hi: 0x8d},
        // Block 0x2e, offset 0x2f
        {value: 0x0000, lo: 0x01},
-       {value: 0x3000, lo: 0xbc, hi: 0xbc},
+       {value: 0x5000, lo: 0xbc, hi: 0xbc},
        // Block 0x2f, offset 0x30
        {value: 0x0000, lo: 0x01},
        {value: 0x8800, lo: 0x80, hi: 0x92},
@@ -6189,17 +6189,17 @@ var charInfoSparseValues = [757]valueRange{
        {value: 0x00dc, lo: 0xad, hi: 0xad},
        // Block 0x40, offset 0x41
        {value: 0x0000, lo: 0x03},
-       {value: 0x3000, lo: 0xac, hi: 0xae},
-       {value: 0x3000, lo: 0xb0, hi: 0xba},
-       {value: 0x3000, lo: 0xbc, hi: 0xbf},
+       {value: 0x5000, lo: 0xac, hi: 0xae},
+       {value: 0x5000, lo: 0xb0, hi: 0xba},
+       {value: 0x5000, lo: 0xbc, hi: 0xbf},
        // Block 0x41, offset 0x42
        {value: 0x0000, lo: 0x03},
-       {value: 0x3000, lo: 0x80, hi: 0x8d},
-       {value: 0x3000, lo: 0x8f, hi: 0xaa},
-       {value: 0x3000, lo: 0xb8, hi: 0xb8},
+       {value: 0x5000, lo: 0x80, hi: 0x8d},
+       {value: 0x5000, lo: 0x8f, hi: 0xaa},
+       {value: 0x5000, lo: 0xb8, hi: 0xb8},
        // Block 0x42, offset 0x43
        {value: 0x0000, lo: 0x01},
-       {value: 0x3000, lo: 0x9b, hi: 0xbf},
+       {value: 0x5000, lo: 0x9b, hi: 0xbf},
        // Block 0x43, offset 0x44
        {value: 0x0000, lo: 0x0e},
        {value: 0x00e6, lo: 0x80, hi: 0x81},
@@ -6231,8 +6231,8 @@ var charInfoSparseValues = [757]valueRange{
        // Block 0x46, offset 0x47
        {value: 0x0000, lo: 0x07},
        {value: 0x1100, lo: 0x80, hi: 0x99},
-       {value: 0x3000, lo: 0x9a, hi: 0x9a},
-       {value: 0x3100, lo: 0x9b, hi: 0x9b},
+       {value: 0x5000, lo: 0x9a, hi: 0x9a},
+       {value: 0x5100, lo: 0x9b, hi: 0x9b},
        {value: 0x9900, lo: 0xa0, hi: 0xa1},
        {value: 0x1100, lo: 0xa2, hi: 0xb7},
        {value: 0x9900, lo: 0xb8, hi: 0xb9},
@@ -6257,35 +6257,35 @@ var charInfoSparseValues = [757]valueRange{
        {value: 0x1100, lo: 0x80, hi: 0xb4},
        {value: 0x9900, lo: 0xb6, hi: 0xb6},
        {value: 0x1100, lo: 0xb7, hi: 0xba},
-       {value: 0x3300, lo: 0xbb, hi: 0xbb},
+       {value: 0x5500, lo: 0xbb, hi: 0xbb},
        {value: 0x1100, lo: 0xbc, hi: 0xbc},
-       {value: 0x3000, lo: 0xbd, hi: 0xbd},
-       {value: 0x3300, lo: 0xbe, hi: 0xbe},
-       {value: 0x3800, lo: 0xbf, hi: 0xbf},
+       {value: 0x5000, lo: 0xbd, hi: 0xbd},
+       {value: 0x5500, lo: 0xbe, hi: 0xbe},
+       {value: 0x5800, lo: 0xbf, hi: 0xbf},
        // Block 0x4a, offset 0x4b
        {value: 0x0000, lo: 0x0a},
-       {value: 0x3300, lo: 0x80, hi: 0x81},
-       {value: 0x3000, lo: 0x82, hi: 0x8a},
-       {value: 0x3000, lo: 0x91, hi: 0x91},
-       {value: 0x3000, lo: 0x97, hi: 0x97},
-       {value: 0x3000, lo: 0xa4, hi: 0xa6},
-       {value: 0x3000, lo: 0xaf, hi: 0xaf},
-       {value: 0x3000, lo: 0xb3, hi: 0xb4},
-       {value: 0x3000, lo: 0xb6, hi: 0xb7},
-       {value: 0x3000, lo: 0xbc, hi: 0xbc},
-       {value: 0x3000, lo: 0xbe, hi: 0xbe},
+       {value: 0x5500, lo: 0x80, hi: 0x81},
+       {value: 0x5000, lo: 0x82, hi: 0x8a},
+       {value: 0x5000, lo: 0x91, hi: 0x91},
+       {value: 0x5000, lo: 0x97, hi: 0x97},
+       {value: 0x5000, lo: 0xa4, hi: 0xa6},
+       {value: 0x5000, lo: 0xaf, hi: 0xaf},
+       {value: 0x5000, lo: 0xb3, hi: 0xb4},
+       {value: 0x5000, lo: 0xb6, hi: 0xb7},
+       {value: 0x5000, lo: 0xbc, hi: 0xbc},
+       {value: 0x5000, lo: 0xbe, hi: 0xbe},
        // Block 0x4b, offset 0x4c
        {value: 0x0000, lo: 0x05},
-       {value: 0x3000, lo: 0x87, hi: 0x89},
-       {value: 0x3000, lo: 0x97, hi: 0x97},
-       {value: 0x3000, lo: 0x9f, hi: 0x9f},
-       {value: 0x3000, lo: 0xb0, hi: 0xb1},
-       {value: 0x3000, lo: 0xb4, hi: 0xbf},
+       {value: 0x5000, lo: 0x87, hi: 0x89},
+       {value: 0x5000, lo: 0x97, hi: 0x97},
+       {value: 0x5000, lo: 0x9f, hi: 0x9f},
+       {value: 0x5000, lo: 0xb0, hi: 0xb1},
+       {value: 0x5000, lo: 0xb4, hi: 0xbf},
        // Block 0x4c, offset 0x4d
        {value: 0x0000, lo: 0x03},
-       {value: 0x3000, lo: 0x80, hi: 0x8e},
-       {value: 0x3000, lo: 0x90, hi: 0x9c},
-       {value: 0x3000, lo: 0xa8, hi: 0xa8},
+       {value: 0x5000, lo: 0x80, hi: 0x8e},
+       {value: 0x5000, lo: 0x90, hi: 0x9c},
+       {value: 0x5000, lo: 0xa8, hi: 0xa8},
        // Block 0x4d, offset 0x4e
        {value: 0x0000, lo: 0x0d},
        {value: 0x00e6, lo: 0x90, hi: 0x91},
@@ -6303,28 +6303,28 @@ var charInfoSparseValues = [757]valueRange{
        {value: 0x00e6, lo: 0xb0, hi: 0xb0},
        // Block 0x4e, offset 0x4f
        {value: 0x0000, lo: 0x0e},
-       {value: 0x3000, lo: 0x80, hi: 0x83},
-       {value: 0x3000, lo: 0x85, hi: 0x87},
-       {value: 0x3000, lo: 0x89, hi: 0x93},
-       {value: 0x3000, lo: 0x95, hi: 0x96},
-       {value: 0x3000, lo: 0x99, hi: 0x9d},
-       {value: 0x3000, lo: 0xa0, hi: 0xa2},
-       {value: 0x3000, lo: 0xa4, hi: 0xa4},
-       {value: 0x3300, lo: 0xa6, hi: 0xa6},
-       {value: 0x3000, lo: 0xa8, hi: 0xa8},
-       {value: 0x3300, lo: 0xaa, hi: 0xab},
-       {value: 0x3000, lo: 0xac, hi: 0xad},
-       {value: 0x3000, lo: 0xaf, hi: 0xb1},
-       {value: 0x3000, lo: 0xb3, hi: 0xb9},
-       {value: 0x3000, lo: 0xbb, hi: 0xbf},
+       {value: 0x5000, lo: 0x80, hi: 0x83},
+       {value: 0x5000, lo: 0x85, hi: 0x87},
+       {value: 0x5000, lo: 0x89, hi: 0x93},
+       {value: 0x5000, lo: 0x95, hi: 0x96},
+       {value: 0x5000, lo: 0x99, hi: 0x9d},
+       {value: 0x5000, lo: 0xa0, hi: 0xa2},
+       {value: 0x5000, lo: 0xa4, hi: 0xa4},
+       {value: 0x5500, lo: 0xa6, hi: 0xa6},
+       {value: 0x5000, lo: 0xa8, hi: 0xa8},
+       {value: 0x5500, lo: 0xaa, hi: 0xab},
+       {value: 0x5000, lo: 0xac, hi: 0xad},
+       {value: 0x5000, lo: 0xaf, hi: 0xb1},
+       {value: 0x5000, lo: 0xb3, hi: 0xb9},
+       {value: 0x5000, lo: 0xbb, hi: 0xbf},
        // Block 0x4f, offset 0x50
        {value: 0x0000, lo: 0x03},
-       {value: 0x3000, lo: 0x80, hi: 0x80},
-       {value: 0x3000, lo: 0x85, hi: 0x89},
-       {value: 0x3000, lo: 0x90, hi: 0xbf},
+       {value: 0x5000, lo: 0x80, hi: 0x80},
+       {value: 0x5000, lo: 0x85, hi: 0x89},
+       {value: 0x5000, lo: 0x90, hi: 0xbf},
        // Block 0x50, offset 0x51
        {value: 0x0000, lo: 0x06},
-       {value: 0x3000, lo: 0x89, hi: 0x89},
+       {value: 0x5000, lo: 0x89, hi: 0x89},
        {value: 0x8800, lo: 0x90, hi: 0x90},
        {value: 0x8800, lo: 0x92, hi: 0x92},
        {value: 0x8800, lo: 0x94, hi: 0x94},
@@ -6348,8 +6348,8 @@ var charInfoSparseValues = [757]valueRange{
        {value: 0x1100, lo: 0xa4, hi: 0xa4},
        {value: 0x8800, lo: 0xa5, hi: 0xa5},
        {value: 0x1100, lo: 0xa6, hi: 0xa6},
-       {value: 0x3000, lo: 0xac, hi: 0xad},
-       {value: 0x3000, lo: 0xaf, hi: 0xb0},
+       {value: 0x5000, lo: 0xac, hi: 0xad},
+       {value: 0x5000, lo: 0xaf, hi: 0xb0},
        {value: 0x8800, lo: 0xbc, hi: 0xbc},
        // Block 0x53, offset 0x54
        {value: 0x0000, lo: 0x0b},
@@ -6370,75 +6370,75 @@ var charInfoSparseValues = [757]valueRange{
        {value: 0x1100, lo: 0xaa, hi: 0xad},
        // Block 0x55, offset 0x56
        {value: 0x0000, lo: 0x01},
-       {value: 0x3300, lo: 0xa9, hi: 0xaa},
+       {value: 0x5500, lo: 0xa9, hi: 0xaa},
        // Block 0x56, offset 0x57
        {value: 0x0000, lo: 0x01},
-       {value: 0x3000, lo: 0xa0, hi: 0xbf},
+       {value: 0x5000, lo: 0xa0, hi: 0xbf},
        // Block 0x57, offset 0x58
        {value: 0x0000, lo: 0x01},
-       {value: 0x3000, lo: 0x80, hi: 0xbf},
+       {value: 0x5000, lo: 0x80, hi: 0xbf},
        // Block 0x58, offset 0x59
        {value: 0x0000, lo: 0x01},
-       {value: 0x3000, lo: 0x80, hi: 0xaa},
+       {value: 0x5000, lo: 0x80, hi: 0xaa},
        // Block 0x59, offset 0x5a
        {value: 0x0000, lo: 0x01},
-       {value: 0x3000, lo: 0x8c, hi: 0x8c},
+       {value: 0x5000, lo: 0x8c, hi: 0x8c},
        // Block 0x5a, offset 0x5b
        {value: 0x0000, lo: 0x01},
-       {value: 0x3000, lo: 0xb4, hi: 0xb6},
+       {value: 0x5000, lo: 0xb4, hi: 0xb6},
        // Block 0x5b, offset 0x5c
        {value: 0x0000, lo: 0x01},
-       {value: 0x3300, lo: 0x9c, hi: 0x9c},
+       {value: 0x5500, lo: 0x9c, hi: 0x9c},
        // Block 0x5c, offset 0x5d
        {value: 0x0000, lo: 0x01},
-       {value: 0x3000, lo: 0xbc, hi: 0xbd},
+       {value: 0x5000, lo: 0xbc, hi: 0xbd},
        // Block 0x5d, offset 0x5e
        {value: 0x0000, lo: 0x01},
        {value: 0x00e6, lo: 0xaf, hi: 0xb1},
        // Block 0x5e, offset 0x5f
        {value: 0x0000, lo: 0x02},
-       {value: 0x3000, lo: 0xaf, hi: 0xaf},
+       {value: 0x5000, lo: 0xaf, hi: 0xaf},
        {value: 0x0009, lo: 0xbf, hi: 0xbf},
        // Block 0x5f, offset 0x60
        {value: 0x0000, lo: 0x01},
        {value: 0x00e6, lo: 0xa0, hi: 0xbf},
        // Block 0x60, offset 0x61
        {value: 0x0000, lo: 0x01},
-       {value: 0x3000, lo: 0x9f, hi: 0x9f},
+       {value: 0x5000, lo: 0x9f, hi: 0x9f},
        // Block 0x61, offset 0x62
        {value: 0x0000, lo: 0x01},
-       {value: 0x3000, lo: 0xb3, hi: 0xb3},
+       {value: 0x5000, lo: 0xb3, hi: 0xb3},
        // Block 0x62, offset 0x63
        {value: 0x0000, lo: 0x01},
-       {value: 0x3000, lo: 0x80, hi: 0x95},
+       {value: 0x5000, lo: 0x80, hi: 0x95},
        // Block 0x63, offset 0x64
        {value: 0x0000, lo: 0x08},
-       {value: 0x3000, lo: 0x80, hi: 0x80},
+       {value: 0x5000, lo: 0x80, hi: 0x80},
        {value: 0x00da, lo: 0xaa, hi: 0xaa},
        {value: 0x00e4, lo: 0xab, hi: 0xab},
        {value: 0x00e8, lo: 0xac, hi: 0xac},
        {value: 0x00de, lo: 0xad, hi: 0xad},
        {value: 0x00e0, lo: 0xae, hi: 0xaf},
-       {value: 0x3000, lo: 0xb6, hi: 0xb6},
-       {value: 0x3000, lo: 0xb8, hi: 0xba},
+       {value: 0x5000, lo: 0xb6, hi: 0xb6},
+       {value: 0x5000, lo: 0xb8, hi: 0xba},
        // Block 0x64, offset 0x65
        {value: 0x0000, lo: 0x01},
-       {value: 0x3000, lo: 0xb1, hi: 0xbf},
+       {value: 0x5000, lo: 0xb1, hi: 0xbf},
        // Block 0x65, offset 0x66
        {value: 0x0000, lo: 0x02},
-       {value: 0x3000, lo: 0x80, hi: 0x8e},
-       {value: 0x3000, lo: 0x92, hi: 0x9f},
+       {value: 0x5000, lo: 0x80, hi: 0x8e},
+       {value: 0x5000, lo: 0x92, hi: 0x9f},
        // Block 0x66, offset 0x67
        {value: 0x0000, lo: 0x02},
-       {value: 0x3000, lo: 0x80, hi: 0x9e},
-       {value: 0x3000, lo: 0xa0, hi: 0xbf},
+       {value: 0x5000, lo: 0x80, hi: 0x9e},
+       {value: 0x5000, lo: 0xa0, hi: 0xbf},
        // Block 0x67, offset 0x68
        {value: 0x0000, lo: 0x02},
-       {value: 0x3000, lo: 0x80, hi: 0x87},
-       {value: 0x3000, lo: 0x90, hi: 0xbe},
+       {value: 0x5000, lo: 0x80, hi: 0x87},
+       {value: 0x5000, lo: 0x90, hi: 0xbe},
        // Block 0x68, offset 0x69
        {value: 0x0000, lo: 0x01},
-       {value: 0x3000, lo: 0x80, hi: 0xbe},
+       {value: 0x5000, lo: 0x80, hi: 0xbe},
        // Block 0x69, offset 0x6a
        {value: 0x0000, lo: 0x02},
        {value: 0x00e6, lo: 0xaf, hi: 0xaf},
@@ -6448,7 +6448,7 @@ var charInfoSparseValues = [757]valueRange{
        {value: 0x00e6, lo: 0xb0, hi: 0xb1},
        // Block 0x6b, offset 0x6c
        {value: 0x0000, lo: 0x01},
-       {value: 0x3000, lo: 0xb0, hi: 0xb0},
+       {value: 0x5000, lo: 0xb0, hi: 0xb0},
        // Block 0x6c, offset 0x6d
        {value: 0x0000, lo: 0x01},
        {value: 0x0009, lo: 0x86, hi: 0x86},
@@ -6489,90 +6489,90 @@ var charInfoSparseValues = [757]valueRange{
        {value: 0x1100, lo: 0x80, hi: 0xa3},
        // Block 0x77, offset 0x78
        {value: 0x0000, lo: 0x01},
-       {value: 0x3300, lo: 0x80, hi: 0xbf},
+       {value: 0x5500, lo: 0x80, hi: 0xbf},
        // Block 0x78, offset 0x79
        {value: 0x0000, lo: 0x09},
-       {value: 0x3300, lo: 0x80, hi: 0x8d},
-       {value: 0x3300, lo: 0x90, hi: 0x90},
-       {value: 0x3300, lo: 0x92, hi: 0x92},
-       {value: 0x3300, lo: 0x95, hi: 0x9e},
-       {value: 0x3300, lo: 0xa0, hi: 0xa0},
-       {value: 0x3300, lo: 0xa2, hi: 0xa2},
-       {value: 0x3300, lo: 0xa5, hi: 0xa6},
-       {value: 0x3300, lo: 0xaa, hi: 0xad},
-       {value: 0x3300, lo: 0xb0, hi: 0xbf},
+       {value: 0x5500, lo: 0x80, hi: 0x8d},
+       {value: 0x5500, lo: 0x90, hi: 0x90},
+       {value: 0x5500, lo: 0x92, hi: 0x92},
+       {value: 0x5500, lo: 0x95, hi: 0x9e},
+       {value: 0x5500, lo: 0xa0, hi: 0xa0},
+       {value: 0x5500, lo: 0xa2, hi: 0xa2},
+       {value: 0x5500, lo: 0xa5, hi: 0xa6},
+       {value: 0x5500, lo: 0xaa, hi: 0xad},
+       {value: 0x5500, lo: 0xb0, hi: 0xbf},
        // Block 0x79, offset 0x7a
        {value: 0x0000, lo: 0x02},
-       {value: 0x3300, lo: 0x80, hi: 0xad},
-       {value: 0x3300, lo: 0xb0, hi: 0xbf},
+       {value: 0x5500, lo: 0x80, hi: 0xad},
+       {value: 0x5500, lo: 0xb0, hi: 0xbf},
        // Block 0x7a, offset 0x7b
        {value: 0x0000, lo: 0x01},
-       {value: 0x3300, lo: 0x80, hi: 0x99},
+       {value: 0x5500, lo: 0x80, hi: 0x99},
        // Block 0x7b, offset 0x7c
        {value: 0x0000, lo: 0x09},
-       {value: 0x3000, lo: 0x80, hi: 0x86},
-       {value: 0x3000, lo: 0x93, hi: 0x97},
-       {value: 0x3300, lo: 0x9d, hi: 0x9d},
+       {value: 0x5000, lo: 0x80, hi: 0x86},
+       {value: 0x5000, lo: 0x93, hi: 0x97},
+       {value: 0x5500, lo: 0x9d, hi: 0x9d},
        {value: 0x001a, lo: 0x9e, hi: 0x9e},
-       {value: 0x3300, lo: 0x9f, hi: 0x9f},
-       {value: 0x3000, lo: 0xa0, hi: 0xa9},
-       {value: 0x3300, lo: 0xaa, hi: 0xb6},
-       {value: 0x3300, lo: 0xb8, hi: 0xbc},
-       {value: 0x3300, lo: 0xbe, hi: 0xbe},
+       {value: 0x5500, lo: 0x9f, hi: 0x9f},
+       {value: 0x5000, lo: 0xa0, hi: 0xa9},
+       {value: 0x5500, lo: 0xaa, hi: 0xb6},
+       {value: 0x5500, lo: 0xb8, hi: 0xbc},
+       {value: 0x5500, lo: 0xbe, hi: 0xbe},
        // Block 0x7c, offset 0x7d
        {value: 0x0000, lo: 0x04},
-       {value: 0x3300, lo: 0x80, hi: 0x81},
-       {value: 0x3300, lo: 0x83, hi: 0x84},
-       {value: 0x3300, lo: 0x86, hi: 0x8e},
-       {value: 0x3000, lo: 0x8f, hi: 0xbf},
+       {value: 0x5500, lo: 0x80, hi: 0x81},
+       {value: 0x5500, lo: 0x83, hi: 0x84},
+       {value: 0x5500, lo: 0x86, hi: 0x8e},
+       {value: 0x5000, lo: 0x8f, hi: 0xbf},
        // Block 0x7d, offset 0x7e
        {value: 0x0000, lo: 0x01},
-       {value: 0x3000, lo: 0x80, hi: 0xb1},
+       {value: 0x5000, lo: 0x80, hi: 0xb1},
        // Block 0x7e, offset 0x7f
        {value: 0x0000, lo: 0x01},
-       {value: 0x3000, lo: 0x93, hi: 0xbf},
+       {value: 0x5000, lo: 0x93, hi: 0xbf},
        // Block 0x7f, offset 0x80
        {value: 0x0000, lo: 0x01},
-       {value: 0x3000, lo: 0x80, hi: 0xbd},
+       {value: 0x5000, lo: 0x80, hi: 0xbd},
        // Block 0x80, offset 0x81
        {value: 0x0000, lo: 0x01},
-       {value: 0x3000, lo: 0x90, hi: 0xbf},
+       {value: 0x5000, lo: 0x90, hi: 0xbf},
        // Block 0x81, offset 0x82
        {value: 0x0000, lo: 0x02},
-       {value: 0x3000, lo: 0x80, hi: 0x8f},
-       {value: 0x3000, lo: 0x92, hi: 0xbf},
+       {value: 0x5000, lo: 0x80, hi: 0x8f},
+       {value: 0x5000, lo: 0x92, hi: 0xbf},
        // Block 0x82, offset 0x83
        {value: 0x0000, lo: 0x02},
-       {value: 0x3000, lo: 0x80, hi: 0x87},
-       {value: 0x3000, lo: 0xb0, hi: 0xbc},
+       {value: 0x5000, lo: 0x80, hi: 0x87},
+       {value: 0x5000, lo: 0xb0, hi: 0xbc},
        // Block 0x83, offset 0x84
        {value: 0x0000, lo: 0x03},
-       {value: 0x3000, lo: 0x90, hi: 0x99},
+       {value: 0x5000, lo: 0x90, hi: 0x99},
        {value: 0x00e6, lo: 0xa0, hi: 0xa6},
-       {value: 0x3000, lo: 0xb0, hi: 0xbf},
+       {value: 0x5000, lo: 0xb0, hi: 0xbf},
        // Block 0x84, offset 0x85
        {value: 0x0000, lo: 0x07},
-       {value: 0x3000, lo: 0x80, hi: 0x84},
-       {value: 0x3000, lo: 0x87, hi: 0x92},
-       {value: 0x3000, lo: 0x94, hi: 0xa6},
-       {value: 0x3000, lo: 0xa8, hi: 0xab},
-       {value: 0x3000, lo: 0xb0, hi: 0xb2},
-       {value: 0x3000, lo: 0xb4, hi: 0xb4},
-       {value: 0x3000, lo: 0xb6, hi: 0xbf},
+       {value: 0x5000, lo: 0x80, hi: 0x84},
+       {value: 0x5000, lo: 0x87, hi: 0x92},
+       {value: 0x5000, lo: 0x94, hi: 0xa6},
+       {value: 0x5000, lo: 0xa8, hi: 0xab},
+       {value: 0x5000, lo: 0xb0, hi: 0xb2},
+       {value: 0x5000, lo: 0xb4, hi: 0xb4},
+       {value: 0x5000, lo: 0xb6, hi: 0xbf},
        // Block 0x85, offset 0x86
        {value: 0x0000, lo: 0x01},
-       {value: 0x3000, lo: 0x80, hi: 0xbc},
+       {value: 0x5000, lo: 0x80, hi: 0xbc},
        // Block 0x86, offset 0x87
        {value: 0x0000, lo: 0x01},
-       {value: 0x3000, lo: 0x81, hi: 0xbf},
+       {value: 0x5000, lo: 0x81, hi: 0xbf},
        // Block 0x87, offset 0x88
        {value: 0x0000, lo: 0x06},
-       {value: 0x3000, lo: 0x82, hi: 0x87},
-       {value: 0x3000, lo: 0x8a, hi: 0x8f},
-       {value: 0x3000, lo: 0x92, hi: 0x97},
-       {value: 0x3000, lo: 0x9a, hi: 0x9c},
-       {value: 0x3000, lo: 0xa0, hi: 0xa6},
-       {value: 0x3000, lo: 0xa8, hi: 0xae},
+       {value: 0x5000, lo: 0x82, hi: 0x87},
+       {value: 0x5000, lo: 0x8a, hi: 0x8f},
+       {value: 0x5000, lo: 0x92, hi: 0x97},
+       {value: 0x5000, lo: 0x9a, hi: 0x9c},
+       {value: 0x5000, lo: 0xa0, hi: 0xa6},
+       {value: 0x5000, lo: 0xa8, hi: 0xae},
        // Block 0x88, offset 0x89
        {value: 0x0000, lo: 0x01},
        {value: 0x00dc, lo: 0xbd, hi: 0xbd},
@@ -6594,7 +6594,7 @@ var charInfoSparseValues = [757]valueRange{
        {value: 0x0009, lo: 0xb9, hi: 0xba},
        // Block 0x8b, offset 0x8c
        {value: 0x0000, lo: 0x06},
-       {value: 0x3300, lo: 0x9e, hi: 0xa4},
+       {value: 0x5500, lo: 0x9e, hi: 0xa4},
        {value: 0x00d8, lo: 0xa5, hi: 0xa6},
        {value: 0x0001, lo: 0xa7, hi: 0xa9},
        {value: 0x00e2, lo: 0xad, hi: 0xad},
@@ -6606,75 +6606,75 @@ var charInfoSparseValues = [757]valueRange{
        {value: 0x00e6, lo: 0x85, hi: 0x89},
        {value: 0x00dc, lo: 0x8a, hi: 0x8b},
        {value: 0x00e6, lo: 0xaa, hi: 0xad},
-       {value: 0x3300, lo: 0xbb, hi: 0xbf},
+       {value: 0x5500, lo: 0xbb, hi: 0xbf},
        // Block 0x8d, offset 0x8e
        {value: 0x0000, lo: 0x01},
-       {value: 0x3300, lo: 0x80, hi: 0x80},
+       {value: 0x5500, lo: 0x80, hi: 0x80},
        // Block 0x8e, offset 0x8f
        {value: 0x0000, lo: 0x01},
        {value: 0x00e6, lo: 0x82, hi: 0x84},
        // Block 0x8f, offset 0x90
        {value: 0x0000, lo: 0x02},
-       {value: 0x3000, lo: 0x80, hi: 0x94},
-       {value: 0x3000, lo: 0x96, hi: 0xbf},
+       {value: 0x5000, lo: 0x80, hi: 0x94},
+       {value: 0x5000, lo: 0x96, hi: 0xbf},
        // Block 0x90, offset 0x91
        {value: 0x0000, lo: 0x08},
-       {value: 0x3000, lo: 0x80, hi: 0x9c},
-       {value: 0x3000, lo: 0x9e, hi: 0x9f},
-       {value: 0x3000, lo: 0xa2, hi: 0xa2},
-       {value: 0x3000, lo: 0xa5, hi: 0xa6},
-       {value: 0x3000, lo: 0xa9, hi: 0xac},
-       {value: 0x3000, lo: 0xae, hi: 0xb9},
-       {value: 0x3000, lo: 0xbb, hi: 0xbb},
-       {value: 0x3000, lo: 0xbd, hi: 0xbf},
+       {value: 0x5000, lo: 0x80, hi: 0x9c},
+       {value: 0x5000, lo: 0x9e, hi: 0x9f},
+       {value: 0x5000, lo: 0xa2, hi: 0xa2},
+       {value: 0x5000, lo: 0xa5, hi: 0xa6},
+       {value: 0x5000, lo: 0xa9, hi: 0xac},
+       {value: 0x5000, lo: 0xae, hi: 0xb9},
+       {value: 0x5000, lo: 0xbb, hi: 0xbb},
+       {value: 0x5000, lo: 0xbd, hi: 0xbf},
        // Block 0x91, offset 0x92
        {value: 0x0000, lo: 0x02},
-       {value: 0x3000, lo: 0x80, hi: 0x83},
-       {value: 0x3000, lo: 0x85, hi: 0xbf},
+       {value: 0x5000, lo: 0x80, hi: 0x83},
+       {value: 0x5000, lo: 0x85, hi: 0xbf},
        // Block 0x92, offset 0x93
        {value: 0x0000, lo: 0x06},
-       {value: 0x3000, lo: 0x80, hi: 0x85},
-       {value: 0x3000, lo: 0x87, hi: 0x8a},
-       {value: 0x3000, lo: 0x8d, hi: 0x94},
-       {value: 0x3000, lo: 0x96, hi: 0x9c},
-       {value: 0x3000, lo: 0x9e, hi: 0xb9},
-       {value: 0x3000, lo: 0xbb, hi: 0xbe},
+       {value: 0x5000, lo: 0x80, hi: 0x85},
+       {value: 0x5000, lo: 0x87, hi: 0x8a},
+       {value: 0x5000, lo: 0x8d, hi: 0x94},
+       {value: 0x5000, lo: 0x96, hi: 0x9c},
+       {value: 0x5000, lo: 0x9e, hi: 0xb9},
+       {value: 0x5000, lo: 0xbb, hi: 0xbe},
        // Block 0x93, offset 0x94
        {value: 0x0000, lo: 0x04},
-       {value: 0x3000, lo: 0x80, hi: 0x84},
-       {value: 0x3000, lo: 0x86, hi: 0x86},
-       {value: 0x3000, lo: 0x8a, hi: 0x90},
-       {value: 0x3000, lo: 0x92, hi: 0xbf},
+       {value: 0x5000, lo: 0x80, hi: 0x84},
+       {value: 0x5000, lo: 0x86, hi: 0x86},
+       {value: 0x5000, lo: 0x8a, hi: 0x90},
+       {value: 0x5000, lo: 0x92, hi: 0xbf},
        // Block 0x94, offset 0x95
        {value: 0x0000, lo: 0x02},
-       {value: 0x3000, lo: 0x80, hi: 0xa5},
-       {value: 0x3000, lo: 0xa8, hi: 0xbf},
+       {value: 0x5000, lo: 0x80, hi: 0xa5},
+       {value: 0x5000, lo: 0xa8, hi: 0xbf},
        // Block 0x95, offset 0x96
        {value: 0x0000, lo: 0x02},
-       {value: 0x3000, lo: 0x80, hi: 0x8b},
-       {value: 0x3000, lo: 0x8e, hi: 0xbf},
+       {value: 0x5000, lo: 0x80, hi: 0x8b},
+       {value: 0x5000, lo: 0x8e, hi: 0xbf},
        // Block 0x96, offset 0x97
        {value: 0x0000, lo: 0x03},
-       {value: 0x3000, lo: 0x80, hi: 0x8a},
-       {value: 0x3000, lo: 0x90, hi: 0xae},
-       {value: 0x3000, lo: 0xb0, hi: 0xbf},
+       {value: 0x5000, lo: 0x80, hi: 0x8a},
+       {value: 0x5000, lo: 0x90, hi: 0xae},
+       {value: 0x5000, lo: 0xb0, hi: 0xbf},
        // Block 0x97, offset 0x98
        {value: 0x0000, lo: 0x01},
-       {value: 0x3000, lo: 0x80, hi: 0x8f},
+       {value: 0x5000, lo: 0x80, hi: 0x8f},
        // Block 0x98, offset 0x99
        {value: 0x0000, lo: 0x01},
-       {value: 0x3000, lo: 0x90, hi: 0x90},
+       {value: 0x5000, lo: 0x90, hi: 0x90},
        // Block 0x99, offset 0x9a
        {value: 0x0000, lo: 0x02},
-       {value: 0x3000, lo: 0x80, hi: 0x82},
-       {value: 0x3000, lo: 0x90, hi: 0xba},
+       {value: 0x5000, lo: 0x80, hi: 0x82},
+       {value: 0x5000, lo: 0x90, hi: 0xba},
        // Block 0x9a, offset 0x9b
        {value: 0x0000, lo: 0x02},
-       {value: 0x3000, lo: 0x80, hi: 0x88},
-       {value: 0x3000, lo: 0x90, hi: 0x91},
+       {value: 0x5000, lo: 0x80, hi: 0x88},
+       {value: 0x5000, lo: 0x90, hi: 0x91},
        // Block 0x9b, offset 0x9c
        {value: 0x0000, lo: 0x01},
-       {value: 0x3300, lo: 0x80, hi: 0x9d},
+       {value: 0x5500, lo: 0x80, hi: 0x9d},
 }
 
 // charInfoLookup: 1152 bytes
similarity index 73%
rename from libgo/go/os/signal/signal_test.go
rename to libgo/go/exp/signal/signal_test.go
index 4568aa9518e7b538fbf569ca92c1664eaec3d652..a7cecb38256313caf9222e5fff40c5f211c33733 100644 (file)
@@ -12,11 +12,13 @@ import (
        "testing"
 )
 
+const sighup = os.UnixSignal(syscall.SIGHUP)
+
 func TestSignal(t *testing.T) {
        // Send this process a SIGHUP.
        syscall.Syscall(syscall.SYS_KILL, uintptr(syscall.Getpid()), syscall.SIGHUP, 0)
 
-       if sig := (<-Incoming).(os.UnixSignal); sig != os.SIGHUP {
-               t.Errorf("signal was %v, want %v", sig, os.SIGHUP)
+       if sig := (<-Incoming).(os.UnixSignal); sig != sighup {
+               t.Errorf("signal was %v, want %v", sig, sighup)
        }
 }
index 7475d352209fc7c308d34c28ba831b70892b63d0..912d467ea08ca87077bd2d035eff1f1956bcd190 100644 (file)
@@ -31,7 +31,7 @@ func init() {
                gcPath = gcName
                return
        }
-       gcPath, _ = exec.LookPath(gcName)
+       gcPath = filepath.Join(runtime.GOROOT(), "/bin/tool/", gcName)
 }
 
 func compile(t *testing.T, dirname, filename string) {
index 5ced285804c1c16496ff05f3d0fc495fd7c9eaff..1919296ea8f6495f0d72f7671dabc100509dce86 100644 (file)
@@ -16,7 +16,7 @@
 //
 // The package is sometimes only imported for the side effect of
 // registering its HTTP handler and the above variables.  To use it
-// this way, simply link this package into your program:
+// this way, link this package into your program:
 //     import _ "expvar"
 //
 package expvar
@@ -83,7 +83,7 @@ func (v *Float) Set(value float64) {
 // Map is a string-to-Var map variable that satisfies the Var interface.
 type Map struct {
        m  map[string]Var
-       mu sync.Mutex
+       mu sync.RWMutex
 }
 
 // KeyValue represents a single entry in a Map.
@@ -93,8 +93,8 @@ type KeyValue struct {
 }
 
 func (v *Map) String() string {
-       v.mu.Lock()
-       defer v.mu.Unlock()
+       v.mu.RLock()
+       defer v.mu.RUnlock()
        b := new(bytes.Buffer)
        fmt.Fprintf(b, "{")
        first := true
@@ -115,8 +115,8 @@ func (v *Map) Init() *Map {
 }
 
 func (v *Map) Get(key string) Var {
-       v.mu.Lock()
-       defer v.mu.Unlock()
+       v.mu.RLock()
+       defer v.mu.RUnlock()
        return v.m[key]
 }
 
@@ -127,12 +127,17 @@ func (v *Map) Set(key string, av Var) {
 }
 
 func (v *Map) Add(key string, delta int64) {
-       v.mu.Lock()
-       defer v.mu.Unlock()
+       v.mu.RLock()
        av, ok := v.m[key]
+       v.mu.RUnlock()
        if !ok {
-               av = new(Int)
-               v.m[key] = av
+               // check again under the write lock
+               v.mu.Lock()
+               if _, ok = v.m[key]; !ok {
+                       av = new(Int)
+                       v.m[key] = av
+               }
+               v.mu.Unlock()
        }
 
        // Add to Int; ignore otherwise.
@@ -143,12 +148,17 @@ func (v *Map) Add(key string, delta int64) {
 
 // AddFloat adds delta to the *Float value stored under the given map key.
 func (v *Map) AddFloat(key string, delta float64) {
-       v.mu.Lock()
-       defer v.mu.Unlock()
+       v.mu.RLock()
        av, ok := v.m[key]
+       v.mu.RUnlock()
        if !ok {
-               av = new(Float)
-               v.m[key] = av
+               // check again under the write lock
+               v.mu.Lock()
+               if _, ok = v.m[key]; !ok {
+                       av = new(Float)
+                       v.m[key] = av
+               }
+               v.mu.Unlock()
        }
 
        // Add to Float; ignore otherwise.
@@ -157,18 +167,15 @@ func (v *Map) AddFloat(key string, delta float64) {
        }
 }
 
-// TODO(rsc): Make sure map access in separate thread is safe.
-func (v *Map) iterate(c chan<- KeyValue) {
+// Do calls f for each entry in the map.
+// The map is locked during the iteration,
+// but existing entries may be concurrently updated.
+func (v *Map) Do(f func(KeyValue)) {
+       v.mu.RLock()
+       defer v.mu.RUnlock()
        for k, v := range v.m {
-               c <- KeyValue{k, v}
+               f(KeyValue{k, v})
        }
-       close(c)
-}
-
-func (v *Map) Iter() <-chan KeyValue {
-       c := make(chan KeyValue)
-       go v.iterate(c)
-       return c
 }
 
 // String is a string variable, and satisfies the Var interface.
@@ -190,8 +197,10 @@ func (f Func) String() string {
 }
 
 // All published variables.
-var vars map[string]Var = make(map[string]Var)
-var mutex sync.Mutex
+var (
+       mutex sync.RWMutex
+       vars  map[string]Var = make(map[string]Var)
+)
 
 // Publish declares a named exported variable. This should be called from a
 // package's init function when it creates its Vars. If the name is already
@@ -207,17 +216,11 @@ func Publish(name string, v Var) {
 
 // Get retrieves a named exported variable.
 func Get(name string) Var {
+       mutex.RLock()
+       defer mutex.RUnlock()
        return vars[name]
 }
 
-// RemoveAll removes all exported variables.
-// This is for tests; don't call this on a real server.
-func RemoveAll() {
-       mutex.Lock()
-       defer mutex.Unlock()
-       vars = make(map[string]Var)
-}
-
 // Convenience functions for creating new exported variables.
 
 func NewInt(name string) *Int {
@@ -244,31 +247,28 @@ func NewString(name string) *String {
        return v
 }
 
-// TODO(rsc): Make sure map access in separate thread is safe.
-func iterate(c chan<- KeyValue) {
+// Do calls f for each exported variable.
+// The global variable map is locked during the iteration,
+// but existing entries may be concurrently updated.
+func Do(f func(KeyValue)) {
+       mutex.RLock()
+       defer mutex.RUnlock()
        for k, v := range vars {
-               c <- KeyValue{k, v}
+               f(KeyValue{k, v})
        }
-       close(c)
-}
-
-func Iter() <-chan KeyValue {
-       c := make(chan KeyValue)
-       go iterate(c)
-       return c
 }
 
 func expvarHandler(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "application/json; charset=utf-8")
        fmt.Fprintf(w, "{\n")
        first := true
-       for name, value := range vars {
+       Do(func(kv KeyValue) {
                if !first {
                        fmt.Fprintf(w, ",\n")
                }
                first = false
-               fmt.Fprintf(w, "%q: %s", name, value)
-       }
+               fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)
+       })
        fmt.Fprintf(w, "\n}\n")
 }
 
@@ -277,11 +277,13 @@ func cmdline() interface{} {
 }
 
 func memstats() interface{} {
-       return runtime.MemStats
+       stats := new(runtime.MemStats)
+       runtime.ReadMemStats(stats)
+       return *stats
 }
 
 func init() {
-       http.Handle("/debug/vars", http.HandlerFunc(expvarHandler))
+       http.HandleFunc("/debug/vars", expvarHandler)
        Publish("cmdline", Func(cmdline))
        Publish("memstats", Func(memstats))
 }
index fc607274b280062572e74895ca57108481ee644a..bbd9dd8d6e94308d085cff3e5ea3c5b0cb7c19c4 100644 (file)
@@ -9,6 +9,14 @@ import (
        "testing"
 )
 
+// RemoveAll removes all exported variables.
+// This is for tests only.
+func RemoveAll() {
+       mutex.Lock()
+       defer mutex.Unlock()
+       vars = make(map[string]Var)
+}
+
 func TestInt(t *testing.T) {
        reqs := NewInt("requests")
        if reqs.i != 0 {
index 964f5541b86c2f53d76c36aee21d3e355562b7ee..c28d0e7207428b23060575193ebe4b0b6fb5082f 100644 (file)
@@ -49,6 +49,7 @@
 
        Integer flags accept 1234, 0664, 0x1234 and may be negative.
        Boolean flags may be 1, 0, t, f, true, false, TRUE, FALSE, True, False.
+       Duration flags accept any input valid for time.ParseDuration.
 
        The default set of command-line flags is controlled by
        top-level functions.  The FlagSet type allows one to define
@@ -62,6 +63,7 @@ package flag
 import (
        "errors"
        "fmt"
+       "io"
        "os"
        "sort"
        "strconv"
@@ -228,6 +230,7 @@ type FlagSet struct {
        args          []string // arguments after flags
        exitOnError   bool     // does the program exit if there's an error?
        errorHandling ErrorHandling
+       output        io.Writer // nil means stderr; use out() accessor
 }
 
 // A Flag represents the state of a flag.
@@ -254,6 +257,19 @@ func sortFlags(flags map[string]*Flag) []*Flag {
        return result
 }
 
+func (f *FlagSet) out() io.Writer {
+       if f.output == nil {
+               return os.Stderr
+       }
+       return f.output
+}
+
+// SetOutput sets the destination for usage and error messages.
+// If output is nil, os.Stderr is used.
+func (f *FlagSet) SetOutput(output io.Writer) {
+       f.output = output
+}
+
 // VisitAll visits the flags in lexicographical order, calling fn for each.
 // It visits all flags, even those not set.
 func (f *FlagSet) VisitAll(fn func(*Flag)) {
@@ -315,15 +331,16 @@ func Set(name, value string) error {
        return commandLine.Set(name, value)
 }
 
-// PrintDefaults prints to standard error the default values of all defined flags in the set.
+// PrintDefaults prints, to standard error unless configured
+// otherwise, the default values of all defined flags in the set.
 func (f *FlagSet) PrintDefaults() {
-       f.VisitAll(func(f *Flag) {
+       f.VisitAll(func(flag *Flag) {
                format := "  -%s=%s: %s\n"
-               if _, ok := f.Value.(*stringValue); ok {
+               if _, ok := flag.Value.(*stringValue); ok {
                        // put quotes on the value
                        format = "  -%s=%q: %s\n"
                }
-               fmt.Fprintf(os.Stderr, format, f.Name, f.DefValue, f.Usage)
+               fmt.Fprintf(f.out(), format, flag.Name, flag.DefValue, flag.Usage)
        })
 }
 
@@ -334,7 +351,7 @@ func PrintDefaults() {
 
 // defaultUsage is the default function to print a usage message.
 func defaultUsage(f *FlagSet) {
-       fmt.Fprintf(os.Stderr, "Usage of %s:\n", f.name)
+       fmt.Fprintf(f.out(), "Usage of %s:\n", f.name)
        f.PrintDefaults()
 }
 
@@ -601,7 +618,7 @@ func (f *FlagSet) Var(value Value, name string, usage string) {
        flag := &Flag{name, usage, value, value.String()}
        _, alreadythere := f.formal[name]
        if alreadythere {
-               fmt.Fprintf(os.Stderr, "%s flag redefined: %s\n", f.name, name)
+               fmt.Fprintf(f.out(), "%s flag redefined: %s\n", f.name, name)
                panic("flag redefinition") // Happens only if flags are declared with identical names
        }
        if f.formal == nil {
@@ -624,7 +641,7 @@ func Var(value Value, name string, usage string) {
 // returns the error.
 func (f *FlagSet) failf(format string, a ...interface{}) error {
        err := fmt.Errorf(format, a...)
-       fmt.Fprintln(os.Stderr, err)
+       fmt.Fprintln(f.out(), err)
        f.usage()
        return err
 }
index 698c15f2c58f681c34befbf4481411af0211a8a7..a9561f269f91ff32bfc31f1f820b28f626407985 100644 (file)
@@ -5,10 +5,12 @@
 package flag_test
 
 import (
+       "bytes"
        . "flag"
        "fmt"
        "os"
        "sort"
+       "strings"
        "testing"
        "time"
 )
@@ -206,6 +208,17 @@ func TestUserDefined(t *testing.T) {
        }
 }
 
+func TestSetOutput(t *testing.T) {
+       var flags FlagSet
+       var buf bytes.Buffer
+       flags.SetOutput(&buf)
+       flags.Init("test", ContinueOnError)
+       flags.Parse([]string{"-unknown"})
+       if out := buf.String(); !strings.Contains(out, "-unknown") {
+               t.Logf("expected output mentioning unknown; got %q", out)
+       }
+}
+
 // This tests that one can reset the flags. This still works but not well, and is
 // superseded by FlagSet.
 func TestChangingArgs(t *testing.T) {
index 504194ce467aeebd114b040c2f144d32cd308a9c..1b02f52baa9fcd2121f987f278c40c1667ee9d70 100644 (file)
@@ -443,6 +443,14 @@ var fmttests = []struct {
        {"%s", nil, "%!s(<nil>)"},
        {"%T", nil, "<nil>"},
        {"%-1", 100, "%!(NOVERB)%!(EXTRA int=100)"},
+
+       // The "<nil>" show up because maps are printed by
+       // first obtaining a list of keys and then looking up
+       // each key.  Since NaNs can be map keys but cannot
+       // be fetched directly, the lookup fails and returns a
+       // zero reflect.Value, which formats as <nil>.
+       // This test is just to check that it shows the two NaNs at all.
+       {"%v", map[float64]int{math.NaN(): 1, math.NaN(): 2}, "map[NaN:<nil> NaN:<nil>]"},
 }
 
 func TestSprintf(t *testing.T) {
@@ -532,13 +540,14 @@ var _ bytes.Buffer
 func TestCountMallocs(t *testing.T) {
        for _, mt := range mallocTest {
                const N = 100
-               runtime.UpdateMemStats()
-               mallocs := 0 - runtime.MemStats.Mallocs
+               memstats := new(runtime.MemStats)
+               runtime.ReadMemStats(memstats)
+               mallocs := 0 - memstats.Mallocs
                for i := 0; i < N; i++ {
                        mt.fn()
                }
-               runtime.UpdateMemStats()
-               mallocs += runtime.MemStats.Mallocs
+               runtime.ReadMemStats(memstats)
+               mallocs += memstats.Mallocs
                if mallocs/N > uint64(mt.count) {
                        t.Errorf("%s: expected %d mallocs, got %d", mt.desc, mt.count, mallocs/N)
                }
index 281525112e14bea7c6fa0cee6dfd95f884fb92d3..36c6aebad0e12f244a7b89384d579e87bbd5d9c4 100644 (file)
@@ -366,6 +366,7 @@ func newScanState(r io.Reader, nlIsSpace, nlIsEnd bool) (s *ss, old ssave) {
        s.fieldLimit = hugeWid
        s.maxWid = hugeWid
        s.validSave = true
+       s.count = 0
        return
 }
 
index 381e2b2d96a2ab433ab30244e660606613911075..3c706a46edda484793f4e7da866e1c89ff112e2e 100644 (file)
@@ -71,6 +71,8 @@ func TestBuild(t *testing.T) {
                        t.Errorf("ScanDir(%#q): %v", tt.dir, err)
                        continue
                }
+               // Don't bother testing import positions.
+               tt.info.ImportPos, tt.info.TestImportPos = info.ImportPos, info.TestImportPos
                if !reflect.DeepEqual(info, tt.info) {
                        t.Errorf("ScanDir(%#q) = %#v, want %#v\n", tt.dir, info, tt.info)
                        continue
index d49846f7d4dea114305d2a2da713509e85dcf6cd..0917e736aa46d17b856feed8fd8b26dd0281508a 100644 (file)
@@ -116,10 +116,11 @@ func envOr(name, def string) string {
 }
 
 type DirInfo struct {
-       Package        string            // Name of package in dir
-       PackageComment *ast.CommentGroup // Package comments from GoFiles
-       ImportPath     string            // Import path of package in dir
-       Imports        []string          // All packages imported by GoFiles
+       Package        string                      // Name of package in dir
+       PackageComment *ast.CommentGroup           // Package comments from GoFiles
+       ImportPath     string                      // Import path of package in dir
+       Imports        []string                    // All packages imported by GoFiles
+       ImportPos      map[string][]token.Position // Source code location of imports
 
        // Source files
        GoFiles  []string // .go files in dir (excluding CgoFiles, TestGoFiles, XTestGoFiles)
@@ -134,9 +135,10 @@ type DirInfo struct {
        CgoLDFLAGS   []string // Cgo LDFLAGS directives
 
        // Test information
-       TestGoFiles  []string // _test.go files in package
-       XTestGoFiles []string // _test.go files outside package
-       TestImports  []string // All packages imported by (X)TestGoFiles
+       TestGoFiles   []string // _test.go files in package
+       XTestGoFiles  []string // _test.go files outside package
+       TestImports   []string // All packages imported by (X)TestGoFiles
+       TestImportPos map[string][]token.Position
 }
 
 func (d *DirInfo) IsCommand() bool {
@@ -223,8 +225,8 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {
 
        var Sfiles []string // files with ".S" (capital S)
        var di DirInfo
-       imported := make(map[string]bool)
-       testImported := make(map[string]bool)
+       imported := make(map[string][]token.Position)
+       testImported := make(map[string][]token.Position)
        fset := token.NewFileSet()
        for _, d := range dirs {
                if d.IsDir() {
@@ -327,9 +329,9 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {
                                        log.Panicf("%s: parser returned invalid quoted string: <%s>", filename, quoted)
                                }
                                if isTest {
-                                       testImported[path] = true
+                                       testImported[path] = append(testImported[path], fset.Position(spec.Pos()))
                                } else {
-                                       imported[path] = true
+                                       imported[path] = append(imported[path], fset.Position(spec.Pos()))
                                }
                                if path == "C" {
                                        if isTest {
@@ -366,12 +368,14 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {
                return nil, fmt.Errorf("%s: no Go source files", dir)
        }
        di.Imports = make([]string, len(imported))
+       di.ImportPos = imported
        i := 0
        for p := range imported {
                di.Imports[i] = p
                i++
        }
        di.TestImports = make([]string, len(testImported))
+       di.TestImportPos = testImported
        i = 0
        for p := range testImported {
                di.TestImports[i] = p
index d73b1315954bc7d5820b72d6cf368eb3bb9c0736..6f0edd4bade3b7fb78dcfe148d018cef9ef89ba5 100644 (file)
@@ -56,7 +56,7 @@ const (
                filePart + `([:.,]` + filePart + `)*`
 )
 
-var matchRx = regexp.MustCompile(`(` + identRx + `)|(` + urlRx + `)`)
+var matchRx = regexp.MustCompile(`(` + urlRx + `)|(` + identRx + `)`)
 
 var (
        html_a      = []byte(`<a href="`)
@@ -87,7 +87,7 @@ func emphasize(w io.Writer, line string, words map[string]string, nice bool) {
                if m == nil {
                        break
                }
-               // m >= 6 (two parenthesized sub-regexps in matchRx, 1st one is identRx)
+               // m >= 6 (two parenthesized sub-regexps in matchRx, 1st one is urlRx)
 
                // write text before match
                commentEscape(w, line[0:m[0]], nice)
@@ -99,8 +99,8 @@ func emphasize(w io.Writer, line string, words map[string]string, nice bool) {
                if words != nil {
                        url, italics = words[string(match)]
                }
-               if m[2] < 0 {
-                       // didn't match against first parenthesized sub-regexp; must be match against urlRx
+               if m[2] >= 0 {
+                       // match against first parenthesized sub-regexp; must be match against urlRx
                        if !italics {
                                // no alternative URL in words list, use match instead
                                url = string(match)
@@ -336,7 +336,7 @@ func blocks(text string) []block {
 
                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
+                       // current line is non-blank, surrounded by blank lines
                        // and the next non-blank line is not indented: this
                        // might be a heading.
                        if head := heading(line); head != "" {
index e8d7f2e4b0f4d95107c478cd392609cf3b4a5ba4..aa21b8d1b30765e8699445f97f8f105f1ee19721 100644 (file)
@@ -5,6 +5,7 @@
 package doc
 
 import (
+       "bytes"
        "reflect"
        "testing"
 )
@@ -81,3 +82,28 @@ func TestBlocks(t *testing.T) {
                }
        }
 }
+
+var emphasizeTests = []struct {
+       in  string
+       out string
+}{
+       {"http://www.google.com/", `<a href="http://www.google.com/">http://www.google.com/</a>`},
+       {"https://www.google.com/", `<a href="https://www.google.com/">https://www.google.com/</a>`},
+       {"http://www.google.com/path.", `<a href="http://www.google.com/path">http://www.google.com/path</a>.`},
+       {"(http://www.google.com/)", `(<a href="http://www.google.com/">http://www.google.com/</a>)`},
+       {"Foo bar http://example.com/ quux!", `Foo bar <a href="http://example.com/">http://example.com/</a> quux!`},
+       {"Hello http://example.com/%2f/ /world.", `Hello <a href="http://example.com/%2f/">http://example.com/%2f/</a> /world.`},
+       {"Lorem http: ipsum //host/path", "Lorem http: ipsum //host/path"},
+       {"javascript://is/not/linked", "javascript://is/not/linked"},
+}
+
+func TestEmphasize(t *testing.T) {
+       for i, tt := range emphasizeTests {
+               var buf bytes.Buffer
+               emphasize(&buf, tt.in, nil, true)
+               out := buf.String()
+               if out != tt.out {
+                       t.Errorf("#%d: mismatch\nhave: %v\nwant: %v", i, out, tt.out)
+               }
+       }
+}
index d4aae8ff05c27a9bbc3410aaa4649bd35235f6e3..9c606315d406f5a498338258cd6491d7c0c4350f 100644 (file)
@@ -68,6 +68,10 @@ const (
        // extract documentation for all package-level declarations,
        // not just exported ones
        AllDecls Mode = 1 << iota
+
+       // show all embedded methods, not just the ones of
+       // invisible (unexported) anonymous fields
+       AllMethods
 )
 
 // New computes the package documentation for the given package AST.
@@ -86,8 +90,8 @@ func New(pkg *ast.Package, importPath string, mode Mode) *Package {
                Filenames:  r.filenames,
                Bugs:       r.bugs,
                Consts:     sortedValues(r.values, token.CONST),
-               Types:      sortedTypes(r.types),
+               Types:      sortedTypes(r.types, mode&AllMethods != 0),
                Vars:       sortedValues(r.values, token.VAR),
-               Funcs:      sortedFuncs(r.funcs),
+               Funcs:      sortedFuncs(r.funcs, true),
        }
 }
index d9ffe47b61406ffefc1559238c641e7aab6b4278..9ffe72032c23acc54394dd53faaeff6c4788885c 100644 (file)
@@ -118,4 +118,5 @@ func test(t *testing.T, mode Mode) {
 func Test(t *testing.T) {
        test(t, 0)
        test(t, AllDecls)
+       test(t, AllMethods)
 }
index 7c59bf9bd60a80b5c9e67227b72671db858cb530..d5b58d266436ed8247fd8c3abe44d637888eaa2b 100644 (file)
@@ -33,8 +33,11 @@ func Examples(pkg *ast.Package) []*Example {
                                continue
                        }
                        examples = append(examples, &Example{
-                               Name:   name[len("Example"):],
-                               Body:   &printer.CommentedNode{f.Body, src.Comments},
+                               Name: name[len("Example"):],
+                               Body: &printer.CommentedNode{
+                                       Node:     f.Body,
+                                       Comments: src.Comments,
+                               },
                                Output: f.Doc.Text(),
                        })
                }
index e6f58ccb3507c9afe6cb5498abb9e5a6f971bbb8..68dd3841bed2bb59efaebedfbfe6dfa0000b7f66 100644 (file)
@@ -23,11 +23,11 @@ func filterIdentList(list []*ast.Ident) []*ast.Ident {
 }
 
 // filterFieldList removes unexported fields (field names) from the field list
-// in place and returns true if fields were removed. Removed fields that are
-// anonymous (embedded) fields are added as embedded types to base. filterType
-// is called with the types of all remaining fields.
+// in place and returns true if fields were removed. Anonymous fields are
+// recorded with the parent type. filterType is called with the types of
+// all remaining fields.
 //
-func (r *reader) filterFieldList(base *baseType, fields *ast.FieldList) (removedFields bool) {
+func (r *reader) filterFieldList(parent *namedType, fields *ast.FieldList) (removedFields bool) {
        if fields == nil {
                return
        }
@@ -37,18 +37,9 @@ func (r *reader) filterFieldList(base *baseType, fields *ast.FieldList) (removed
                keepField := false
                if n := len(field.Names); n == 0 {
                        // anonymous field
-                       name, imp := baseTypeName(field.Type)
+                       name := r.recordAnonymousField(parent, field.Type)
                        if ast.IsExported(name) {
-                               // we keep the field - in this case r.readDecl
-                               // will take care of adding the embedded type
                                keepField = true
-                       } else if base != nil && !imp {
-                               // we don't keep the field - add it as an embedded
-                               // type so we won't loose its methods, if any
-                               if embedded := r.lookupType(name); embedded != nil {
-                                       _, ptr := field.Type.(*ast.StarExpr)
-                                       base.addEmbeddedType(embedded, ptr)
-                               }
                        }
                } else {
                        field.Names = filterIdentList(field.Names)
@@ -86,7 +77,7 @@ func (r *reader) filterParamList(fields *ast.FieldList) {
 // in place. If fields (or methods) have been removed, the corresponding
 // struct or interface type has the Incomplete field set to true. 
 //
-func (r *reader) filterType(base *baseType, typ ast.Expr) {
+func (r *reader) filterType(parent *namedType, typ ast.Expr) {
        switch t := typ.(type) {
        case *ast.Ident:
                // nothing to do
@@ -95,14 +86,14 @@ func (r *reader) filterType(base *baseType, typ ast.Expr) {
        case *ast.ArrayType:
                r.filterType(nil, t.Elt)
        case *ast.StructType:
-               if r.filterFieldList(base, t.Fields) {
+               if r.filterFieldList(parent, t.Fields) {
                        t.Incomplete = true
                }
        case *ast.FuncType:
                r.filterParamList(t.Params)
                r.filterParamList(t.Results)
        case *ast.InterfaceType:
-               if r.filterFieldList(base, t.Methods) {
+               if r.filterFieldList(parent, t.Methods) {
                        t.Incomplete = true
                }
        case *ast.MapType:
@@ -150,6 +141,10 @@ func (r *reader) filterDecl(decl ast.Decl) bool {
                d.Specs = r.filterSpecList(d.Specs)
                return len(d.Specs) > 0
        case *ast.FuncDecl:
+               // ok to filter these methods early because any
+               // conflicting method will be filtered here, too -
+               // thus, removing these methods early will not lead
+               // to the false removal of possible conflicts
                return ast.IsExported(d.Name.Name)
        }
        return false
index 9c6f0816b60f81e864accc1ea477e559d63a9ffd..dcf49f68fd378d5e070fd7dc3cf38f2a876db2a9 100644 (file)
@@ -89,7 +89,7 @@ func (mset methodSet) add(m *Func) {
 }
 
 // ----------------------------------------------------------------------------
-// Base types
+// Named types
 
 // baseTypeName returns the name of the base type of x (or "")
 // and whether the type is imported or not.
@@ -110,31 +110,23 @@ func baseTypeName(x ast.Expr) (name string, imported bool) {
        return
 }
 
-// embeddedType describes the type of an anonymous field.
+// A namedType represents a named unqualified (package local, or possibly
+// predeclared) type. The namedType for a type name is always found via
+// reader.lookupType.
 //
-type embeddedType struct {
-       typ *baseType // the corresponding base type
-       ptr bool      // if set, the anonymous field type is a pointer
-}
-
-type baseType struct {
+type namedType struct {
        doc  string       // doc comment for type
-       name string       // local type name (excluding package qualifier)
+       name string       // type name
        decl *ast.GenDecl // nil if declaration hasn't been seen yet
 
+       isEmbedded bool                // true if this type is embedded
+       isStruct   bool                // true if this type is a struct
+       embedded   map[*namedType]bool // true if the embedded type is a pointer
+
        // associated declarations
        values  []*Value // consts and vars
        funcs   methodSet
        methods methodSet
-
-       isEmbedded bool           // true if this type is embedded
-       isStruct   bool           // true if this type is a struct
-       embedded   []embeddedType // list of embedded types
-}
-
-func (typ *baseType) addEmbeddedType(e *baseType, isPtr bool) {
-       e.isEmbedded = true
-       typ.embedded = append(typ.embedded, embeddedType{e, isPtr})
 }
 
 // ----------------------------------------------------------------------------
@@ -158,12 +150,10 @@ type reader struct {
        // declarations
        imports map[string]int
        values  []*Value // consts and vars
-       types   map[string]*baseType
+       types   map[string]*namedType
        funcs   methodSet
 }
 
-// isVisible reports whether name is visible in the documentation.
-//
 func (r *reader) isVisible(name string) bool {
        return r.mode&AllDecls != 0 || ast.IsExported(name)
 }
@@ -173,7 +163,7 @@ func (r *reader) isVisible(name string) bool {
 // type with the given name but no associated declaration
 // is added to the type map.
 //
-func (r *reader) lookupType(name string) *baseType {
+func (r *reader) lookupType(name string) *namedType {
        if name == "" || name == "_" {
                return nil // no type docs for anonymous types
        }
@@ -181,15 +171,34 @@ func (r *reader) lookupType(name string) *baseType {
                return typ
        }
        // type not found - add one without declaration
-       typ := &baseType{
-               name:    name,
-               funcs:   make(methodSet),
-               methods: make(methodSet),
+       typ := &namedType{
+               name:     name,
+               embedded: make(map[*namedType]bool),
+               funcs:    make(methodSet),
+               methods:  make(methodSet),
        }
        r.types[name] = typ
        return typ
 }
 
+// recordAnonymousField registers fieldType as the type of an
+// anonymous field in the parent type. If the field is imported
+// (qualified name) or the parent is nil, the field is ignored.
+// The function returns the field name.
+//
+func (r *reader) recordAnonymousField(parent *namedType, fieldType ast.Expr) (fname string) {
+       fname, imp := baseTypeName(fieldType)
+       if parent == nil || imp {
+               return
+       }
+       if ftype := r.lookupType(fname); ftype != nil {
+               ftype.isEmbedded = true
+               _, ptr := fieldType.(*ast.StarExpr)
+               parent.embedded[ftype] = ptr
+       }
+       return
+}
+
 func (r *reader) readDoc(comment *ast.CommentGroup) {
        // By convention there should be only one package comment
        // but collect all of them if there are more then one.
@@ -232,7 +241,7 @@ func (r *reader) readValue(decl *ast.GenDecl) {
                switch {
                case s.Type != nil:
                        // a type is present; determine its name
-                       if n, imp := baseTypeName(s.Type); !imp && r.isVisible(n) {
+                       if n, imp := baseTypeName(s.Type); !imp {
                                name = n
                        }
                case decl.Tok == token.CONST:
@@ -267,8 +276,7 @@ func (r *reader) readValue(decl *ast.GenDecl) {
        const threshold = 0.75
        if domName != "" && domFreq >= int(float64(len(decl.Specs))*threshold) {
                // typed entries are sufficiently frequent
-               typ := r.lookupType(domName)
-               if typ != nil {
+               if typ := r.lookupType(domName); typ != nil {
                        values = &typ.values // associate with that type
                }
        }
@@ -321,22 +329,14 @@ func (r *reader) readType(decl *ast.GenDecl, spec *ast.TypeSpec) {
        decl.Doc = nil // doc consumed - remove from AST
        typ.doc = doc.Text()
 
-       // look for anonymous fields that might contribute methods
+       // record anonymous fields (they may contribute methods)
+       // (some fields may have been recorded already when filtering
+       // exports, but that's ok)
        var list []*ast.Field
        list, typ.isStruct = fields(spec.Type)
        for _, field := range list {
                if len(field.Names) == 0 {
-                       // anonymous field - add corresponding field type to typ
-                       n, imp := baseTypeName(field.Type)
-                       if imp {
-                               // imported type - we don't handle this case
-                               // at the moment
-                               return
-                       }
-                       if embedded := r.lookupType(n); embedded != nil {
-                               _, ptr := field.Type.(*ast.StarExpr)
-                               typ.addEmbeddedType(embedded, ptr)
-                       }
+                       r.recordAnonymousField(typ, field.Type)
                }
        }
 }
@@ -347,7 +347,7 @@ func (r *reader) readFunc(fun *ast.FuncDecl) {
        // strip function body
        fun.Body = nil
 
-       // determine if it should be associated with a type
+       // associate methods with the receiver type, if any
        if fun.Recv != nil {
                // method
                recvTypeName, imp := baseTypeName(fun.Recv.List[0].Type)
@@ -356,24 +356,10 @@ func (r *reader) readFunc(fun *ast.FuncDecl) {
                        // don't show this method
                        return
                }
-               var typ *baseType
-               if r.isVisible(recvTypeName) {
-                       // visible recv type: if not found, add it to r.types
-                       typ = r.lookupType(recvTypeName)
-               } else {
-                       // invisible recv type: if not found, do not add it
-                       // (invisible embedded types are added before this
-                       // phase, so if the type doesn't exist yet, we don't
-                       // care about this method)
-                       typ = r.types[recvTypeName]
-               }
-               if typ != nil {
-                       // associate method with the type
-                       // (if the type is not exported, it may be embedded
-                       // somewhere so we need to collect the method anyway)
+               if typ := r.lookupType(recvTypeName); typ != nil {
                        typ.methods.set(fun)
                }
-               // otherwise don't show the method
+               // otherwise ignore the method
                // TODO(gri): There may be exported methods of non-exported types
                // that can be called because of exported values (consts, vars, or
                // function results) of that type. Could determine if that is the
@@ -381,8 +367,7 @@ func (r *reader) readFunc(fun *ast.FuncDecl) {
                return
        }
 
-       // perhaps a factory function
-       // determine result type, if any
+       // associate factory functions with the first visible result type, if any
        if fun.Type.Results.NumFields() >= 1 {
                res := fun.Type.Results.List[0]
                if len(res.Names) <= 1 {
@@ -391,7 +376,7 @@ func (r *reader) readFunc(fun *ast.FuncDecl) {
                        // be more than one result)
                        if n, imp := baseTypeName(res.Type); !imp && r.isVisible(n) {
                                if typ := r.lookupType(n); typ != nil {
-                                       // associate Func with typ
+                                       // associate function with typ
                                        typ.funcs.set(fun)
                                        return
                                }
@@ -476,7 +461,7 @@ func (r *reader) readPackage(pkg *ast.Package, mode Mode) {
        r.filenames = make([]string, len(pkg.Files))
        r.imports = make(map[string]int)
        r.mode = mode
-       r.types = make(map[string]*baseType)
+       r.types = make(map[string]*namedType)
        r.funcs = make(methodSet)
 
        // sort package files before reading them so that the
@@ -506,6 +491,7 @@ var predeclaredTypes = map[string]bool{
        "byte":       true,
        "complex64":  true,
        "complex128": true,
+       "error":      true,
        "float32":    true,
        "float64":    true,
        "int":        true,
@@ -513,6 +499,7 @@ var predeclaredTypes = map[string]bool{
        "int16":      true,
        "int32":      true,
        "int64":      true,
+       "rune":       true,
        "string":     true,
        "uint":       true,
        "uint8":      true,
@@ -554,24 +541,23 @@ func customizeRecv(f *Func, recvTypeName string, embeddedIsPtr bool, level int)
        return &newF
 }
 
-// collectEmbeddedMethods collects the embedded methods from
-// all processed embedded types found in info in mset.
+// collectEmbeddedMethods collects the embedded methods of typ in mset.
 //
-func collectEmbeddedMethods(mset methodSet, typ *baseType, recvTypeName string, embeddedIsPtr bool, level int) {
-       for _, e := range typ.embedded {
+func (r *reader) collectEmbeddedMethods(mset methodSet, typ *namedType, recvTypeName string, embeddedIsPtr bool, level int) {
+       for embedded, isPtr := range typ.embedded {
                // Once an embedded type is embedded as a pointer type
                // all embedded types in those types are treated like
                // pointer types for the purpose of the receiver type
                // computation; i.e., embeddedIsPtr is sticky for this
                // embedding hierarchy.
-               thisEmbeddedIsPtr := embeddedIsPtr || e.ptr
-               for _, m := range e.typ.methods {
+               thisEmbeddedIsPtr := embeddedIsPtr || isPtr
+               for _, m := range embedded.methods {
                        // only top-level methods are embedded
                        if m.Level == 0 {
                                mset.add(customizeRecv(m, recvTypeName, thisEmbeddedIsPtr, level))
                        }
                }
-               collectEmbeddedMethods(mset, e.typ, recvTypeName, thisEmbeddedIsPtr, level+1)
+               r.collectEmbeddedMethods(mset, embedded, recvTypeName, thisEmbeddedIsPtr, level+1)
        }
 }
 
@@ -582,7 +568,7 @@ func (r *reader) computeMethodSets() {
                // collect embedded methods for t
                if t.isStruct {
                        // struct
-                       collectEmbeddedMethods(t.methods, t, t.name, false, 1)
+                       r.collectEmbeddedMethods(t.methods, t, t.name, false, 1)
                } else {
                        // interface
                        // TODO(gri) fix this
@@ -607,6 +593,8 @@ func (r *reader) cleanupTypes() {
                        r.values = append(r.values, t.values...)
                        // 2) move factory functions
                        for name, f := range t.funcs {
+                               // in a correct AST, package-level function names
+                               // are all different - no need to check for conflicts
                                r.funcs[name] = f
                        }
                        // 3) move methods
@@ -689,7 +677,7 @@ func sortedValues(m []*Value, tok token.Token) []*Value {
        return list
 }
 
-func sortedTypes(m map[string]*baseType) []*Type {
+func sortedTypes(m map[string]*namedType, allMethods bool) []*Type {
        list := make([]*Type, len(m))
        i := 0
        for _, t := range m {
@@ -699,8 +687,8 @@ func sortedTypes(m map[string]*baseType) []*Type {
                        Decl:    t.decl,
                        Consts:  sortedValues(t.values, token.CONST),
                        Vars:    sortedValues(t.values, token.VAR),
-                       Funcs:   sortedFuncs(t.funcs),
-                       Methods: sortedFuncs(t.methods),
+                       Funcs:   sortedFuncs(t.funcs, true),
+                       Methods: sortedFuncs(t.methods, allMethods),
                }
                i++
        }
@@ -714,12 +702,24 @@ func sortedTypes(m map[string]*baseType) []*Type {
        return list
 }
 
-func sortedFuncs(m methodSet) []*Func {
+func removeStar(s string) string {
+       if len(s) > 0 && s[0] == '*' {
+               return s[1:]
+       }
+       return s
+}
+
+func sortedFuncs(m methodSet, allMethods bool) []*Func {
        list := make([]*Func, len(m))
        i := 0
        for _, m := range m {
-               // exclude conflict entries
-               if m.Decl != nil {
+               // determine which methods to include
+               switch {
+               case m.Decl == nil:
+                       // exclude conflict entry
+               case allMethods, m.Level == 0, !ast.IsExported(removeStar(m.Orig)):
+                       // forced inclusion, method not embedded, or method
+                       // embedded but original receiver type not exported
                        list[i] = m
                        i++
                }
diff --git a/libgo/go/go/doc/testdata/a.2.golden b/libgo/go/go/doc/testdata/a.2.golden
new file mode 100644 (file)
index 0000000..24db02d
--- /dev/null
@@ -0,0 +1,13 @@
+// comment 0  comment 1 
+PACKAGE a
+
+IMPORTPATH
+       testdata/a
+
+FILENAMES
+       testdata/a0.go
+       testdata/a1.go
+
+BUGS
+       // bug0 
+       // bug1 
diff --git a/libgo/go/go/doc/testdata/b.2.golden b/libgo/go/go/doc/testdata/b.2.golden
new file mode 100644 (file)
index 0000000..7c33300
--- /dev/null
@@ -0,0 +1,43 @@
+// 
+PACKAGE b
+
+IMPORTPATH
+       testdata/b
+
+IMPORTS
+       a
+
+FILENAMES
+       testdata/b.go
+
+CONSTANTS
+       // 
+       const Pi = 3.14 // Pi
+
+
+VARIABLES
+       // 
+       var MaxInt int  // MaxInt
+
+
+FUNCTIONS
+       // 
+       func F(x int) int
+
+       // Always under the package functions list. 
+       func NotAFactory() int
+
+       // Associated with uint type if AllDecls is set. 
+       func UintFactory() uint
+
+
+TYPES
+       // 
+       type T struct{} // T
+
+       // 
+       var V T // v
+
+       // 
+       func (x *T) M()
+
diff --git a/libgo/go/go/doc/testdata/c.2.golden b/libgo/go/go/doc/testdata/c.2.golden
new file mode 100644 (file)
index 0000000..e21959b
--- /dev/null
@@ -0,0 +1,48 @@
+// 
+PACKAGE c
+
+IMPORTPATH
+       testdata/c
+
+IMPORTS
+       a
+
+FILENAMES
+       testdata/c.go
+
+TYPES
+       // A (should see this) 
+       type A struct{}
+
+       // B (should see this) 
+       type B struct{}
+
+       // C (should see this) 
+       type C struct{}
+
+       // D (should see this) 
+       type D struct{}
+
+       // E1 (should see this) 
+       type E1 struct{}
+
+       // E (should see this for E2 and E3) 
+       type E2 struct{}
+
+       // E (should see this for E2 and E3) 
+       type E3 struct{}
+
+       // E4 (should see this) 
+       type E4 struct{}
+
+       // 
+       type T1 struct{}
+
+       // 
+       func (t1 *T1) M()
+
+       // T2 must not show methods of local T1 
+       type T2 struct {
+               a.T1    // not the same as locally declared T1
+       }
+
diff --git a/libgo/go/go/doc/testdata/d.2.golden b/libgo/go/go/doc/testdata/d.2.golden
new file mode 100644 (file)
index 0000000..c005199
--- /dev/null
@@ -0,0 +1,104 @@
+// 
+PACKAGE d
+
+IMPORTPATH
+       testdata/d
+
+FILENAMES
+       testdata/d1.go
+       testdata/d2.go
+
+CONSTANTS
+       // CBx constants should appear before CAx constants. 
+       const (
+               CB2     = iota  // before CB1
+               CB1             // before CB0
+               CB0             // at end
+       )
+
+       // CAx constants should appear after CBx constants. 
+       const (
+               CA2     = iota  // before CA1
+               CA1             // before CA0
+               CA0             // at end
+       )
+
+       // C0 should be first. 
+       const C0 = 0
+
+       // C1 should be second. 
+       const C1 = 1
+
+       // C2 should be third. 
+       const C2 = 2
+
+       // 
+       const (
+               // Single const declarations inside ()'s are considered ungrouped
+               // and show up in sorted order.
+               Cungrouped = 0
+       )
+
+
+VARIABLES
+       // VBx variables should appear before VAx variables. 
+       var (
+               VB2     int     // before VB1
+               VB1     int     // before VB0
+               VB0     int     // at end
+       )
+
+       // VAx variables should appear after VBx variables. 
+       var (
+               VA2     int     // before VA1
+               VA1     int     // before VA0
+               VA0     int     // at end
+       )
+
+       // V0 should be first. 
+       var V0 uintptr
+
+       // V1 should be second. 
+       var V1 uint
+
+       // V2 should be third. 
+       var V2 int
+
+       // 
+       var (
+               // Single var declarations inside ()'s are considered ungrouped
+               // and show up in sorted order.
+               Vungrouped = 0
+       )
+
+
+FUNCTIONS
+       // F0 should be first. 
+       func F0()
+
+       // F1 should be second. 
+       func F1()
+
+       // F2 should be third. 
+       func F2()
+
+
+TYPES
+       // T0 should be first. 
+       type T0 struct{}
+
+       // T1 should be second. 
+       type T1 struct{}
+
+       // T2 should be third. 
+       type T2 struct{}
+
+       // TG0 should be first. 
+       type TG0 struct{}
+
+       // TG1 should be second. 
+       type TG1 struct{}
+
+       // TG2 should be third. 
+       type TG2 struct{}
+
index 3b128f7be8bda3f74c33fbceaefd46a035157048..096a50ff41f9b2ecb21073759676c6a10285a0ac 100644 (file)
@@ -1,4 +1,4 @@
-// 
+// The package e is a go/doc test for embedded methods. 
 PACKAGE e
 
 IMPORTPATH
@@ -8,7 +8,7 @@ FILENAMES
        testdata/e.go
 
 TYPES
-       // T1 has no (top-level) M method due to conflict. 
+       // T1 has no embedded (level 1) M method due to conflict. 
        type T1 struct {
                // contains filtered or unexported fields
        }
@@ -29,3 +29,14 @@ TYPES
        // T3.M should appear as method of T3. 
        func (T3) M()
 
+       // 
+       type T4 struct{}
+
+       // T4.M should appear as method of T5 only if AllMethods is set. 
+       func (*T4) M()
+
+       // 
+       type T5 struct {
+               T4
+       }
+
index d05602d82cb9dab9ea5c3c9e6692c9539e62656a..28be74a1fd6a52c70974f35218cd0b4222f0081e 100644 (file)
@@ -1,4 +1,4 @@
-// 
+// The package e is a go/doc test for embedded methods. 
 PACKAGE e
 
 IMPORTPATH
@@ -8,7 +8,7 @@ FILENAMES
        testdata/e.go
 
 TYPES
-       // T1 has no (top-level) M method due to conflict. 
+       // T1 has no embedded (level 1) M method due to conflict. 
        type T1 struct {
                t1
                t2
@@ -31,6 +31,17 @@ TYPES
        // T3.M should appear as method of T3. 
        func (T3) M()
 
+       // 
+       type T4 struct{}
+
+       // T4.M should appear as method of T5 only if AllMethods is set. 
+       func (*T4) M()
+
+       // 
+       type T5 struct {
+               T4
+       }
+
        // 
        type t1 struct{}
 
diff --git a/libgo/go/go/doc/testdata/e.2.golden b/libgo/go/go/doc/testdata/e.2.golden
new file mode 100644 (file)
index 0000000..f9a2b81
--- /dev/null
@@ -0,0 +1,45 @@
+// The package e is a go/doc test for embedded methods. 
+PACKAGE e
+
+IMPORTPATH
+       testdata/e
+
+FILENAMES
+       testdata/e.go
+
+TYPES
+       // T1 has no embedded (level 1) M method due to conflict. 
+       type T1 struct {
+               // contains filtered or unexported fields
+       }
+
+       // T2 has only M as top-level method. 
+       type T2 struct {
+               // contains filtered or unexported fields
+       }
+
+       // T2.M should appear as method of T2. 
+       func (T2) M()
+
+       // T3 has only M as top-level method. 
+       type T3 struct {
+               // contains filtered or unexported fields
+       }
+
+       // T3.M should appear as method of T3. 
+       func (T3) M()
+
+       // 
+       type T4 struct{}
+
+       // T4.M should appear as method of T5 only if AllMethods is set. 
+       func (*T4) M()
+
+       // 
+       type T5 struct {
+               T4
+       }
+
+       // T4.M should appear as method of T5 only if AllMethods is set. 
+       func (*T5) M()
+
index 8ea6a83b66aaca3f92af772705760556d1e56329..526a91f4f00b8706fb4c218218cc4a7af1d0eb69 100644 (file)
@@ -2,9 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Embedding tests.
-// TODO(gri): This should be comprehensive.
-
+// The package e is a go/doc test for embedded methods.
 package e
 
 // ----------------------------------------------------------------------------
@@ -20,7 +18,7 @@ type t2 struct{}
 // t2.M should not appear as method in a Tx type.
 func (t2) M() {}
 
-// T1 has no (top-level) M method due to conflict.
+// T1 has no embedded (level 1) M method due to conflict.
 type T1 struct {
        t1
        t2
@@ -56,3 +54,26 @@ type T3 struct {
 
 // T3.M should appear as method of T3.
 func (T3) M() {}
+
+// ----------------------------------------------------------------------------
+// Don't show conflicting methods M embedded via an exported and non-exported
+// type.
+
+// T1 has no embedded (level 1) M method due to conflict.
+type T4 struct {
+       t2
+       T2
+}
+
+// ----------------------------------------------------------------------------
+// Don't show embedded methods of exported anonymous fields unless AllMethods
+// is set.
+
+type T4 struct{}
+
+// T4.M should appear as method of T5 only if AllMethods is set.
+func (*T4) M() {}
+
+type T5 struct {
+       T4
+}
diff --git a/libgo/go/go/doc/testdata/f.0.golden b/libgo/go/go/doc/testdata/f.0.golden
new file mode 100644 (file)
index 0000000..8175901
--- /dev/null
@@ -0,0 +1,13 @@
+// The package f is a go/doc test for functions and factory ...
+PACKAGE f
+
+IMPORTPATH
+       testdata/f
+
+FILENAMES
+       testdata/f.go
+
+FUNCTIONS
+       // Exported must always be visible. Was issue 2824. 
+       func Exported() private
+
diff --git a/libgo/go/go/doc/testdata/f.1.golden b/libgo/go/go/doc/testdata/f.1.golden
new file mode 100644 (file)
index 0000000..ba68e88
--- /dev/null
@@ -0,0 +1,16 @@
+// The package f is a go/doc test for functions and factory ...
+PACKAGE f
+
+IMPORTPATH
+       testdata/f
+
+FILENAMES
+       testdata/f.go
+
+TYPES
+       // 
+       type private struct{}
+
+       // Exported must always be visible. Was issue 2824. 
+       func Exported() private
+
diff --git a/libgo/go/go/doc/testdata/f.2.golden b/libgo/go/go/doc/testdata/f.2.golden
new file mode 100644 (file)
index 0000000..8175901
--- /dev/null
@@ -0,0 +1,13 @@
+// The package f is a go/doc test for functions and factory ...
+PACKAGE f
+
+IMPORTPATH
+       testdata/f
+
+FILENAMES
+       testdata/f.go
+
+FUNCTIONS
+       // Exported must always be visible. Was issue 2824. 
+       func Exported() private
+
diff --git a/libgo/go/go/doc/testdata/f.go b/libgo/go/go/doc/testdata/f.go
new file mode 100644 (file)
index 0000000..a3051e1
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The package f is a go/doc test for functions and factory methods.
+package f
+
+// ----------------------------------------------------------------------------
+// Factory functions for non-exported types must not get lost.
+
+type private struct{}
+
+// Exported must always be visible. Was issue 2824.
+func Exported() private {}
diff --git a/libgo/go/go/doc/testdata/testing.2.golden b/libgo/go/go/doc/testdata/testing.2.golden
new file mode 100644 (file)
index 0000000..15a9039
--- /dev/null
@@ -0,0 +1,156 @@
+// Package testing provides support for automated testing of Go ...
+PACKAGE testing
+
+IMPORTPATH
+       testdata/testing
+
+IMPORTS
+       bytes
+       flag
+       fmt
+       io
+       os
+       runtime
+       runtime/pprof
+       strconv
+       strings
+       time
+
+FILENAMES
+       testdata/benchmark.go
+       testdata/example.go
+       testdata/testing.go
+
+FUNCTIONS
+       // An internal function but exported because it is cross-package; ...
+       func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample)
+
+       // An internal function but exported because it is cross-package; ...
+       func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks []InternalBenchmark)
+
+       // 
+       func RunExamples(examples []InternalExample) (ok bool)
+
+       // 
+       func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool)
+
+       // Short reports whether the -test.short flag is set. 
+       func Short() bool
+
+
+TYPES
+       // B is a type passed to Benchmark functions to manage benchmark ...
+       type B struct {
+               N int
+               // contains filtered or unexported fields
+       }
+
+       // Error is equivalent to Log() followed by Fail(). 
+       func (c *B) Error(args ...interface{})
+
+       // Errorf is equivalent to Logf() followed by Fail(). 
+       func (c *B) Errorf(format string, args ...interface{})
+
+       // Fail marks the function as having failed but continues ...
+       func (c *B) Fail()
+
+       // FailNow marks the function as having failed and stops its ...
+       func (c *B) FailNow()
+
+       // Failed returns whether the function has failed. 
+       func (c *B) Failed() bool
+
+       // Fatal is equivalent to Log() followed by FailNow(). 
+       func (c *B) Fatal(args ...interface{})
+
+       // Fatalf is equivalent to Logf() followed by FailNow(). 
+       func (c *B) Fatalf(format string, args ...interface{})
+
+       // Log formats its arguments using default formatting, analogous ...
+       func (c *B) Log(args ...interface{})
+
+       // Logf formats its arguments according to the format, analogous ...
+       func (c *B) Logf(format string, args ...interface{})
+
+       // ResetTimer sets the elapsed benchmark time to zero. It does not ...
+       func (b *B) ResetTimer()
+
+       // SetBytes records the number of bytes processed in a single ...
+       func (b *B) SetBytes(n int64)
+
+       // StartTimer starts timing a test.  This function is called ...
+       func (b *B) StartTimer()
+
+       // StopTimer stops timing a test.  This can be used to pause the ...
+       func (b *B) StopTimer()
+
+       // The results of a benchmark run. 
+       type BenchmarkResult struct {
+               N       int             // The number of iterations.
+               T       time.Duration   // The total time taken.
+               Bytes   int64           // Bytes processed in one iteration.
+       }
+
+       // Benchmark benchmarks a single function. Useful for creating ...
+       func Benchmark(f func(b *B)) BenchmarkResult
+
+       // 
+       func (r BenchmarkResult) NsPerOp() int64
+
+       // 
+       func (r BenchmarkResult) String() string
+
+       // An internal type but exported because it is cross-package; part ...
+       type InternalBenchmark struct {
+               Name    string
+               F       func(b *B)
+       }
+
+       // 
+       type InternalExample struct {
+               Name    string
+               F       func()
+               Output  string
+       }
+
+       // An internal type but exported because it is cross-package; part ...
+       type InternalTest struct {
+               Name    string
+               F       func(*T)
+       }
+
+       // T is a type passed to Test functions to manage test state and ...
+       type T struct {
+               // contains filtered or unexported fields
+       }
+
+       // Error is equivalent to Log() followed by Fail(). 
+       func (c *T) Error(args ...interface{})
+
+       // Errorf is equivalent to Logf() followed by Fail(). 
+       func (c *T) Errorf(format string, args ...interface{})
+
+       // Fail marks the function as having failed but continues ...
+       func (c *T) Fail()
+
+       // FailNow marks the function as having failed and stops its ...
+       func (c *T) FailNow()
+
+       // Failed returns whether the function has failed. 
+       func (c *T) Failed() bool
+
+       // Fatal is equivalent to Log() followed by FailNow(). 
+       func (c *T) Fatal(args ...interface{})
+
+       // Fatalf is equivalent to Logf() followed by FailNow(). 
+       func (c *T) Fatalf(format string, args ...interface{})
+
+       // Log formats its arguments using default formatting, analogous ...
+       func (c *T) Log(args ...interface{})
+
+       // Logf formats its arguments according to the format, analogous ...
+       func (c *T) Logf(format string, args ...interface{})
+
+       // Parallel signals that this test is to be run in parallel with ...
+       func (t *T) Parallel()
+
index 5f3b4d4a740b8dcc58649c710ba2bc0dda625ecf..25935fb42bb8b369be3791b28c2cb83224f0b5c0 100644 (file)
@@ -76,6 +76,7 @@ func (p *printer) setComment(g *ast.CommentGroup) {
        }
        p.comments[0] = g
        p.cindex = 0
+       p.nextComment() // get comment ready for use
 }
 
 type exprListMode uint
index 52dfff6f4b369863f55f3197971ea4d4a2f929c9..fe99e675eb05653a301d5c1cd0c67534825df8bf 100644 (file)
@@ -12,7 +12,6 @@ import (
        "go/token"
        "io"
        "os"
-       "path/filepath"
        "strconv"
        "strings"
        "text/tabwriter"
@@ -52,11 +51,12 @@ type printer struct {
        fset *token.FileSet
 
        // Current state
-       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
+       output      bytes.Buffer // raw printer result
+       indent      int          // current indentation
+       mode        pmode        // current printer mode
+       impliedSemi bool         // if set, a linebreak implies a semicolon
+       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
@@ -73,6 +73,11 @@ type printer struct {
        cindex          int                 // current comment index
        useNodeComments bool                // if not set, ignore lead and line comments of nodes
 
+       // Information about p.comments[p.cindex]; set up by nextComment.
+       comment        *ast.CommentGroup // = p.comments[p.cindex]; or nil
+       commentOffset  int               // = p.posFor(p.comments[p.cindex].List[0].Pos()).Offset; or infinity
+       commentNewline bool              // true if the comment group contains newlines
+
        // Cache of already computed node sizes.
        nodeSizes map[ast.Node]int
 
@@ -89,6 +94,42 @@ func (p *printer) init(cfg *Config, fset *token.FileSet, nodeSizes map[ast.Node]
        p.cachedPos = -1
 }
 
+// commentsHaveNewline reports whether a list of comments belonging to
+// an *ast.CommentGroup contains newlines. Because the position information
+// may only be partially correct, we also have to read the comment text.
+func (p *printer) commentsHaveNewline(list []*ast.Comment) bool {
+       // len(list) > 0
+       line := p.lineFor(list[0].Pos())
+       for i, c := range list {
+               if i > 0 && p.lineFor(list[i].Pos()) != line {
+                       // not all comments on the same line
+                       return true
+               }
+               if t := c.Text; len(t) >= 2 && (t[1] == '/' || strings.Contains(t, "\n")) {
+                       return true
+               }
+       }
+       _ = line
+       return false
+}
+
+func (p *printer) nextComment() {
+       for p.cindex < len(p.comments) {
+               c := p.comments[p.cindex]
+               p.cindex++
+               if list := c.List; len(list) > 0 {
+                       p.comment = c
+                       p.commentOffset = p.posFor(list[0].Pos()).Offset
+                       p.commentNewline = p.commentsHaveNewline(list)
+                       return
+               }
+               // we should not reach here (correct ASTs don't have empty
+               // ast.CommentGroup nodes), but be conservative and try again
+       }
+       // no more comments
+       p.commentOffset = infinity
+}
+
 func (p *printer) internalError(msg ...interface{}) {
        if debug {
                fmt.Print(p.pos.String() + ": ")
@@ -204,8 +245,7 @@ func (p *printer) writeItem(pos token.Position, data string, isLit bool) {
        }
        if debug {
                // do not update p.pos - use write0
-               _, filename := filepath.Split(pos.Filename)
-               fmt.Fprintf(&p.output, "[%s:%d:%d]", filename, pos.Line, pos.Column)
+               fmt.Fprintf(&p.output, "/*%s*/", pos)
        }
        p.writeString(data, isLit)
        p.last = p.pos
@@ -618,12 +658,13 @@ func (p *printer) writeCommentSuffix(needsLinebreak bool) (wroteNewline, dropped
 //
 func (p *printer) intersperseComments(next token.Position, tok token.Token) (wroteNewline, droppedFF bool) {
        var last *ast.Comment
-       for ; p.commentBefore(next); p.cindex++ {
-               for _, c := range p.comments[p.cindex].List {
+       for p.commentBefore(next) {
+               for _, c := range p.comment.List {
                        p.writeCommentPrefix(p.posFor(c.Pos()), next, last, c, tok.IsKeyword())
                        p.writeComment(c)
                        last = c
                }
+               p.nextComment()
        }
 
        if last != nil {
@@ -735,22 +776,24 @@ func mayCombine(prev token.Token, next byte) (b bool) {
 // printed, followed by the actual token.
 //
 func (p *printer) print(args ...interface{}) {
-       for _, f := range args {
-               next := p.pos // estimated position of next item
-               data := ""
-               isLit := false
-               var tok token.Token
+       for _, arg := range args {
+               // information about the current arg
+               var data string
+               var isLit bool
+               var impliedSemi bool // value for p.impliedSemi after this arg
 
-               switch x := f.(type) {
+               switch x := arg.(type) {
                case pmode:
                        // toggle printer mode
                        p.mode ^= x
+                       continue
+
                case whiteSpace:
                        if x == ignore {
                                // don't add ignore's to the buffer; they
                                // may screw up "correcting" unindents (see
                                // LabeledStmt)
-                               break
+                               continue
                        }
                        i := len(p.wsbuf)
                        if i == cap(p.wsbuf) {
@@ -762,13 +805,27 @@ func (p *printer) print(args ...interface{}) {
                        }
                        p.wsbuf = p.wsbuf[0 : i+1]
                        p.wsbuf[i] = x
+                       if x == newline || x == formfeed {
+                               // newlines affect the current state (p.impliedSemi)
+                               // and not the state after printing arg (impliedSemi)
+                               // because comments can be interspersed before the arg
+                               // in this case
+                               p.impliedSemi = false
+                       }
+                       p.lastTok = token.ILLEGAL
+                       continue
+
                case *ast.Ident:
                        data = x.Name
-                       tok = token.IDENT
+                       impliedSemi = true
+                       p.lastTok = token.IDENT
+
                case *ast.BasicLit:
                        data = x.Value
                        isLit = true
-                       tok = x.Kind
+                       impliedSemi = true
+                       p.lastTok = x.Kind
+
                case token.Token:
                        s := x.String()
                        if mayCombine(p.lastTok, s[0]) {
@@ -785,30 +842,40 @@ func (p *printer) print(args ...interface{}) {
                                p.wsbuf[0] = ' '
                        }
                        data = s
-                       tok = x
+                       // some keywords followed by a newline imply a semicolon
+                       switch x {
+                       case token.BREAK, token.CONTINUE, token.FALLTHROUGH, token.RETURN,
+                               token.INC, token.DEC, token.RPAREN, token.RBRACK, token.RBRACE:
+                               impliedSemi = true
+                       }
+                       p.lastTok = x
+
                case token.Pos:
                        if x.IsValid() {
-                               next = p.posFor(x) // accurate position of next item
+                               p.pos = p.posFor(x) // accurate position of next item
                        }
-                       tok = p.lastTok
+                       continue
+
                case string:
                        // incorrect AST - print error message
                        data = x
                        isLit = true
-                       tok = token.STRING
+                       impliedSemi = true
+                       p.lastTok = token.STRING
+
                default:
-                       fmt.Fprintf(os.Stderr, "print: unsupported argument %v (%T)\n", f, f)
+                       fmt.Fprintf(os.Stderr, "print: unsupported argument %v (%T)\n", arg, arg)
                        panic("go/printer type")
                }
-               p.lastTok = tok
-               p.pos = next
+               // data != ""
 
-               if data != "" {
-                       wroteNewline, droppedFF := p.flush(next, tok)
+               next := p.pos // estimated/accurate position of next item
+               wroteNewline, droppedFF := p.flush(next, p.lastTok)
 
-                       // 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)
+               // intersperse extra newlines if present in the source and
+               // if they don't cause extra semicolons (don't do this in
+               // flush as it will cause extra newlines at the end of a file)
+               if !p.impliedSemi {
                        n := nlimit(next.Line - p.pos.Line)
                        // don't exceed maxNewlines if we already wrote one
                        if wroteNewline && n == maxNewlines {
@@ -820,22 +887,25 @@ func (p *printer) print(args ...interface{}) {
                                        ch = '\f' // use formfeed since we dropped one before
                                }
                                p.writeByteN(ch, n)
+                               impliedSemi = false
                        }
-
-                       p.writeItem(next, data, isLit)
                }
+
+               p.writeItem(next, data, isLit)
+               p.impliedSemi = impliedSemi
        }
 }
 
-// commentBefore returns true iff the current comment occurs
-// before the next position in the source code.
+// commentBefore returns true iff the current comment group occurs
+// before the next position in the source code and printing it does
+// not introduce implicit semicolons.
 //
-func (p *printer) commentBefore(next token.Position) bool {
-       return p.cindex < len(p.comments) && p.posFor(p.comments[p.cindex].List[0].Pos()).Offset < next.Offset
+func (p *printer) commentBefore(next token.Position) (result bool) {
+       return p.commentOffset < next.Offset && (!p.impliedSemi || !p.commentNewline)
 }
 
-// Flush prints any pending comments and whitespace occurring textually
-// before the position of the next token tok. The Flush result indicates
+// flush prints any pending comments and whitespace occurring textually
+// before the position of the next token tok. The flush result indicates
 // if a newline was written or if a formfeed was dropped from the whitespace
 // buffer.
 //
@@ -915,6 +985,9 @@ func (p *printer) printNode(node interface{}) error {
        // if there are no comments, use node comments
        p.useNodeComments = p.comments == nil
 
+       // get comments ready for use
+       p.nextComment()
+
        // format node
        switch n := node.(type) {
        case ast.Expr:
@@ -1068,6 +1141,8 @@ func (cfg *Config) fprint(output io.Writer, fset *token.FileSet, node interface{
        if err = p.printNode(node); err != nil {
                return
        }
+       // print outstanding comments
+       p.impliedSemi = false // EOF acts like a newline
        p.flush(token.Position{Offset: infinity, Line: infinity}, token.EOF)
 
        // redirect output through a trimmer to eliminate trailing whitespace
@@ -1108,7 +1183,7 @@ func (cfg *Config) fprint(output io.Writer, fset *token.FileSet, node interface{
 }
 
 // A CommentedNode bundles an AST node and corresponding comments.
-// It may be provided as argument to any of the FPrint functions.
+// It may be provided as argument to any of the Fprint functions.
 //
 type CommentedNode struct {
        Node     interface{} // *ast.File, or ast.Expr, ast.Decl, ast.Spec, or ast.Stmt
index 525fcc1595f7ef096b51f3457892365fafb88e99..9adf48cda6136e496edb45cc3d5822e0783d5286 100644 (file)
@@ -171,14 +171,14 @@ func TestLineComments(t *testing.T) {
        `
 
        fset := token.NewFileSet()
-       ast1, err1 := parser.ParseFile(fset, "", src, parser.ParseComments)
-       if err1 != nil {
-               panic(err1)
+       f, err := parser.ParseFile(fset, "", src, parser.ParseComments)
+       if err != nil {
+               panic(err) // error in test
        }
 
        var buf bytes.Buffer
        fset = token.NewFileSet() // use the wrong file set
-       Fprint(&buf, fset, ast1)
+       Fprint(&buf, fset, f)
 
        nlines := 0
        for _, ch := range buf.Bytes() {
@@ -190,6 +190,7 @@ func TestLineComments(t *testing.T) {
        const expected = 3
        if nlines < expected {
                t.Errorf("got %d, expected %d\n", nlines, expected)
+               t.Errorf("result:\n%s", buf.Bytes())
        }
 }
 
@@ -198,9 +199,11 @@ func init() {
        const name = "foobar"
        var buf bytes.Buffer
        if err := Fprint(&buf, fset, &ast.Ident{Name: name}); err != nil {
-               panic(err)
+               panic(err) // error in test
        }
-       if s := buf.String(); s != name {
+       // in debug mode, the result contains additional information;
+       // ignore it
+       if s := buf.String(); !debug && s != name {
                panic("got " + s + ", want " + name)
        }
 }
@@ -211,7 +214,7 @@ func TestBadNodes(t *testing.T) {
        const res = "package p\nBadDecl\n"
        f, err := parser.ParseFile(fset, "", src, parser.ParseComments)
        if err == nil {
-               t.Errorf("expected illegal program")
+               t.Error("expected illegal program") // error in test
        }
        var buf bytes.Buffer
        Fprint(&buf, fset, f)
@@ -219,3 +222,61 @@ func TestBadNodes(t *testing.T) {
                t.Errorf("got %q, expected %q", buf.String(), res)
        }
 }
+
+// Print and parse f with 
+func testComment(t *testing.T, f *ast.File, srclen int, comment *ast.Comment) {
+       f.Comments[0].List[0] = comment
+       var buf bytes.Buffer
+       for offs := 0; offs <= srclen; offs++ {
+               buf.Reset()
+               // Printing f should result in a correct program no
+               // matter what the (incorrect) comment position is.
+               if err := Fprint(&buf, fset, f); err != nil {
+                       t.Error(err)
+               }
+               if _, err := parser.ParseFile(fset, "", buf.Bytes(), 0); err != nil {
+                       t.Fatalf("incorrect program for pos = %d:\n%s", comment.Slash, buf.String())
+               }
+               // Position information is just an offset.
+               // Move comment one byte down in the source.
+               comment.Slash++
+       }
+}
+
+// Verify that the printer produces always produces a correct program
+// even if the position information of comments introducing newlines
+// is incorrect.
+func TestBadComments(t *testing.T) {
+       const src = `
+// first comment - text and position changed by test
+package p
+import "fmt"
+const pi = 3.14 // rough circle
+var (
+       x, y, z int = 1, 2, 3
+       u, v float64
+)
+func fibo(n int) {
+       if n < 2 {
+               return n /* seed values */
+       }
+       return fibo(n-1) + fibo(n-2)
+}
+`
+
+       f, err := parser.ParseFile(fset, "", src, parser.ParseComments)
+       if err != nil {
+               t.Error(err) // error in test
+       }
+
+       comment := f.Comments[0].List[0]
+       pos := comment.Pos()
+       if fset.Position(pos).Offset != 1 {
+               t.Error("expected offset 1") // error in test
+       }
+
+       testComment(t, f, len(src), &ast.Comment{pos, "//-style comment"})
+       testComment(t, f, len(src), &ast.Comment{pos, "/*-style comment */"})
+       testComment(t, f, len(src), &ast.Comment{pos, "/*-style \n comment */"})
+       testComment(t, f, len(src), &ast.Comment{pos, "/*-style comment \n\n\n */"})
+}
index 89e341c5f97f9d42f4a255c47f1ee2f8e337aa2b..c85297f58314248b1ea3092b5716799d19b70d10 100644 (file)
@@ -6,7 +6,7 @@
 // provided in a variety of forms (see the various Parse* functions); the
 // output is an abstract syntax tree (AST) representing the Go source. The
 // parser is invoked through one of the Parse* functions.
-//
+
 package parser
 
 import (
index 7c72c0a46b922372165aa1b1f47185962d95ac14..0aabfe34c416d89632a0cca1eac5d7ef1fe49fdc 100644 (file)
@@ -8,7 +8,7 @@
 //
 //     var s scanner.Scanner
 //     fset := token.NewFileSet()  // position information is relative to fset
-//      file := fset.AddFile(filename, fset.Base(), len(src))  // register file
+//     file := fset.AddFile(filename, fset.Base(), len(src))  // register file
 //     s.Init(file, src, nil /* no error handler */, 0)
 //     for {
 //             pos, tok, lit := s.Scan()
@@ -53,36 +53,36 @@ type Scanner struct {
        ErrorCount int // number of errors encountered
 }
 
-// Read the next Unicode char into S.ch.
-// S.ch < 0 means end-of-file.
+// Read the next Unicode char into s.ch.
+// s.ch < 0 means end-of-file.
 //
-func (S *Scanner) next() {
-       if S.rdOffset < len(S.src) {
-               S.offset = S.rdOffset
-               if S.ch == '\n' {
-                       S.lineOffset = S.offset
-                       S.file.AddLine(S.offset)
+func (s *Scanner) next() {
+       if s.rdOffset < len(s.src) {
+               s.offset = s.rdOffset
+               if s.ch == '\n' {
+                       s.lineOffset = s.offset
+                       s.file.AddLine(s.offset)
                }
-               r, w := rune(S.src[S.rdOffset]), 1
+               r, w := rune(s.src[s.rdOffset]), 1
                switch {
                case r == 0:
-                       S.error(S.offset, "illegal character NUL")
+                       s.error(s.offset, "illegal character NUL")
                case r >= 0x80:
                        // not ASCII
-                       r, w = utf8.DecodeRune(S.src[S.rdOffset:])
+                       r, w = utf8.DecodeRune(s.src[s.rdOffset:])
                        if r == utf8.RuneError && w == 1 {
-                               S.error(S.offset, "illegal UTF-8 encoding")
+                               s.error(s.offset, "illegal UTF-8 encoding")
                        }
                }
-               S.rdOffset += w
-               S.ch = r
+               s.rdOffset += w
+               s.ch = r
        } else {
-               S.offset = len(S.src)
-               if S.ch == '\n' {
-                       S.lineOffset = S.offset
-                       S.file.AddLine(S.offset)
+               s.offset = len(s.src)
+               if s.ch == '\n' {
+                       s.lineOffset = s.offset
+                       s.file.AddLine(s.offset)
                }
-               S.ch = -1 // eof
+               s.ch = -1 // eof
        }
 }
 
@@ -96,7 +96,7 @@ const (
        dontInsertSemis                  // do not automatically insert semicolons - for testing only
 )
 
-// Init prepares the scanner S to tokenize the text src by setting the
+// Init prepares the scanner s to tokenize the text src by setting the
 // scanner at the beginning of src. The scanner uses the file set file
 // for position information and it adds line information for each line.
 // It is ok to re-use the same file when re-scanning the same file as
@@ -111,37 +111,37 @@ const (
 // Note that Init may call err if there is an error in the first character
 // of the file.
 //
-func (S *Scanner) Init(file *token.File, src []byte, err ErrorHandler, mode Mode) {
+func (s *Scanner) Init(file *token.File, src []byte, err ErrorHandler, mode Mode) {
        // Explicitly initialize all fields since a scanner may be reused.
        if file.Size() != len(src) {
                panic("file size does not match src len")
        }
-       S.file = file
-       S.dir, _ = filepath.Split(file.Name())
-       S.src = src
-       S.err = err
-       S.mode = mode
+       s.file = file
+       s.dir, _ = filepath.Split(file.Name())
+       s.src = src
+       s.err = err
+       s.mode = mode
 
-       S.ch = ' '
-       S.offset = 0
-       S.rdOffset = 0
-       S.lineOffset = 0
-       S.insertSemi = false
-       S.ErrorCount = 0
+       s.ch = ' '
+       s.offset = 0
+       s.rdOffset = 0
+       s.lineOffset = 0
+       s.insertSemi = false
+       s.ErrorCount = 0
 
-       S.next()
+       s.next()
 }
 
-func (S *Scanner) error(offs int, msg string) {
-       if S.err != nil {
-               S.err.Error(S.file.Position(S.file.Pos(offs)), msg)
+func (s *Scanner) error(offs int, msg string) {
+       if s.err != nil {
+               s.err.Error(s.file.Position(s.file.Pos(offs)), msg)
        }
-       S.ErrorCount++
+       s.ErrorCount++
 }
 
 var prefix = []byte("//line ")
 
-func (S *Scanner) interpretLineComment(text []byte) {
+func (s *Scanner) interpretLineComment(text []byte) {
        if bytes.HasPrefix(text, prefix) {
                // get filename and line number, if any
                if i := bytes.LastIndex(text, []byte{':'}); i > 0 {
@@ -150,88 +150,88 @@ func (S *Scanner) interpretLineComment(text []byte) {
                                filename := filepath.Clean(string(text[len(prefix):i]))
                                if !filepath.IsAbs(filename) {
                                        // make filename relative to current directory
-                                       filename = filepath.Join(S.dir, filename)
+                                       filename = filepath.Join(s.dir, filename)
                                }
                                // update scanner position
-                               S.file.AddLineInfo(S.lineOffset+len(text)+1, filename, line) // +len(text)+1 since comment applies to next line
+                               s.file.AddLineInfo(s.lineOffset+len(text)+1, filename, line) // +len(text)+1 since comment applies to next line
                        }
                }
        }
 }
 
-func (S *Scanner) scanComment() string {
-       // initial '/' already consumed; S.ch == '/' || S.ch == '*'
-       offs := S.offset - 1 // position of initial '/'
+func (s *Scanner) scanComment() string {
+       // initial '/' already consumed; s.ch == '/' || s.ch == '*'
+       offs := s.offset - 1 // position of initial '/'
 
-       if S.ch == '/' {
+       if s.ch == '/' {
                //-style comment
-               S.next()
-               for S.ch != '\n' && S.ch >= 0 {
-                       S.next()
+               s.next()
+               for s.ch != '\n' && s.ch >= 0 {
+                       s.next()
                }
-               if offs == S.lineOffset {
+               if offs == s.lineOffset {
                        // comment starts at the beginning of the current line
-                       S.interpretLineComment(S.src[offs:S.offset])
+                       s.interpretLineComment(s.src[offs:s.offset])
                }
                goto exit
        }
 
        /*-style comment */
-       S.next()
-       for S.ch >= 0 {
-               ch := S.ch
-               S.next()
-               if ch == '*' && S.ch == '/' {
-                       S.next()
+       s.next()
+       for s.ch >= 0 {
+               ch := s.ch
+               s.next()
+               if ch == '*' && s.ch == '/' {
+                       s.next()
                        goto exit
                }
        }
 
-       S.error(offs, "comment not terminated")
+       s.error(offs, "comment not terminated")
 
 exit:
-       return string(S.src[offs:S.offset])
+       return string(s.src[offs:s.offset])
 }
 
-func (S *Scanner) findLineEnd() bool {
+func (s *Scanner) findLineEnd() bool {
        // initial '/' already consumed
 
        defer func(offs int) {
                // reset scanner state to where it was upon calling findLineEnd
-               S.ch = '/'
-               S.offset = offs
-               S.rdOffset = offs + 1
-               S.next() // consume initial '/' again
-       }(S.offset - 1)
+               s.ch = '/'
+               s.offset = offs
+               s.rdOffset = offs + 1
+               s.next() // consume initial '/' again
+       }(s.offset - 1)
 
        // read ahead until a newline, EOF, or non-comment token is found
-       for S.ch == '/' || S.ch == '*' {
-               if S.ch == '/' {
+       for s.ch == '/' || s.ch == '*' {
+               if s.ch == '/' {
                        //-style comment always contains a newline
                        return true
                }
                /*-style comment: look for newline */
-               S.next()
-               for S.ch >= 0 {
-                       ch := S.ch
+               s.next()
+               for s.ch >= 0 {
+                       ch := s.ch
                        if ch == '\n' {
                                return true
                        }
-                       S.next()
-                       if ch == '*' && S.ch == '/' {
-                               S.next()
+                       s.next()
+                       if ch == '*' && s.ch == '/' {
+                               s.next()
                                break
                        }
                }
-               S.skipWhitespace() // S.insertSemi is set
-               if S.ch < 0 || S.ch == '\n' {
+               s.skipWhitespace() // s.insertSemi is set
+               if s.ch < 0 || s.ch == '\n' {
                        return true
                }
-               if S.ch != '/' {
+               if s.ch != '/' {
                        // non-comment token
                        return false
                }
-               S.next() // consume '/'
+               s.next() // consume '/'
        }
 
        return false
@@ -245,12 +245,12 @@ func isDigit(ch rune) bool {
        return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch)
 }
 
-func (S *Scanner) scanIdentifier() string {
-       offs := S.offset
-       for isLetter(S.ch) || isDigit(S.ch) {
-               S.next()
+func (s *Scanner) scanIdentifier() string {
+       offs := s.offset
+       for isLetter(s.ch) || isDigit(s.ch) {
+               s.next()
        }
-       return string(S.src[offs:S.offset])
+       return string(s.src[offs:s.offset])
 }
 
 func digitVal(ch rune) int {
@@ -265,176 +265,176 @@ func digitVal(ch rune) int {
        return 16 // larger than any legal digit val
 }
 
-func (S *Scanner) scanMantissa(base int) {
-       for digitVal(S.ch) < base {
-               S.next()
+func (s *Scanner) scanMantissa(base int) {
+       for digitVal(s.ch) < base {
+               s.next()
        }
 }
 
-func (S *Scanner) scanNumber(seenDecimalPoint bool) (token.Token, string) {
-       // digitVal(S.ch) < 10
-       offs := S.offset
+func (s *Scanner) scanNumber(seenDecimalPoint bool) (token.Token, string) {
+       // digitVal(s.ch) < 10
+       offs := s.offset
        tok := token.INT
 
        if seenDecimalPoint {
                offs--
                tok = token.FLOAT
-               S.scanMantissa(10)
+               s.scanMantissa(10)
                goto exponent
        }
 
-       if S.ch == '0' {
+       if s.ch == '0' {
                // int or float
-               offs := S.offset
-               S.next()
-               if S.ch == 'x' || S.ch == 'X' {
+               offs := s.offset
+               s.next()
+               if s.ch == 'x' || s.ch == 'X' {
                        // hexadecimal int
-                       S.next()
-                       S.scanMantissa(16)
-                       if S.offset-offs <= 2 {
+                       s.next()
+                       s.scanMantissa(16)
+                       if s.offset-offs <= 2 {
                                // only scanned "0x" or "0X"
-                               S.error(offs, "illegal hexadecimal number")
+                               s.error(offs, "illegal hexadecimal number")
                        }
                } else {
                        // octal int or float
                        seenDecimalDigit := false
-                       S.scanMantissa(8)
-                       if S.ch == '8' || S.ch == '9' {
+                       s.scanMantissa(8)
+                       if s.ch == '8' || s.ch == '9' {
                                // illegal octal int or float
                                seenDecimalDigit = true
-                               S.scanMantissa(10)
+                               s.scanMantissa(10)
                        }
-                       if S.ch == '.' || S.ch == 'e' || S.ch == 'E' || S.ch == 'i' {
+                       if s.ch == '.' || s.ch == 'e' || s.ch == 'E' || s.ch == 'i' {
                                goto fraction
                        }
                        // octal int
                        if seenDecimalDigit {
-                               S.error(offs, "illegal octal number")
+                               s.error(offs, "illegal octal number")
                        }
                }
                goto exit
        }
 
        // decimal int or float
-       S.scanMantissa(10)
+       s.scanMantissa(10)
 
 fraction:
-       if S.ch == '.' {
+       if s.ch == '.' {
                tok = token.FLOAT
-               S.next()
-               S.scanMantissa(10)
+               s.next()
+               s.scanMantissa(10)
        }
 
 exponent:
-       if S.ch == 'e' || S.ch == 'E' {
+       if s.ch == 'e' || s.ch == 'E' {
                tok = token.FLOAT
-               S.next()
-               if S.ch == '-' || S.ch == '+' {
-                       S.next()
+               s.next()
+               if s.ch == '-' || s.ch == '+' {
+                       s.next()
                }
-               S.scanMantissa(10)
+               s.scanMantissa(10)
        }
 
-       if S.ch == 'i' {
+       if s.ch == 'i' {
                tok = token.IMAG
-               S.next()
+               s.next()
        }
 
 exit:
-       return tok, string(S.src[offs:S.offset])
+       return tok, string(s.src[offs:s.offset])
 }
 
-func (S *Scanner) scanEscape(quote rune) {
-       offs := S.offset
+func (s *Scanner) scanEscape(quote rune) {
+       offs := s.offset
 
        var i, base, max uint32
-       switch S.ch {
+       switch s.ch {
        case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', quote:
-               S.next()
+               s.next()
                return
        case '0', '1', '2', '3', '4', '5', '6', '7':
                i, base, max = 3, 8, 255
        case 'x':
-               S.next()
+               s.next()
                i, base, max = 2, 16, 255
        case 'u':
-               S.next()
+               s.next()
                i, base, max = 4, 16, unicode.MaxRune
        case 'U':
-               S.next()
+               s.next()
                i, base, max = 8, 16, unicode.MaxRune
        default:
-               S.next() // always make progress
-               S.error(offs, "unknown escape sequence")
+               s.next() // always make progress
+               s.error(offs, "unknown escape sequence")
                return
        }
 
        var x uint32
-       for ; i > 0 && S.ch != quote && S.ch >= 0; i-- {
-               d := uint32(digitVal(S.ch))
+       for ; i > 0 && s.ch != quote && s.ch >= 0; i-- {
+               d := uint32(digitVal(s.ch))
                if d >= base {
-                       S.error(S.offset, "illegal character in escape sequence")
+                       s.error(s.offset, "illegal character in escape sequence")
                        break
                }
                x = x*base + d
-               S.next()
+               s.next()
        }
        // in case of an error, consume remaining chars
-       for ; i > 0 && S.ch != quote && S.ch >= 0; i-- {
-               S.next()
+       for ; i > 0 && s.ch != quote && s.ch >= 0; i-- {
+               s.next()
        }
        if x > max || 0xd800 <= x && x < 0xe000 {
-               S.error(offs, "escape sequence is invalid Unicode code point")
+               s.error(offs, "escape sequence is invalid Unicode code point")
        }
 }
 
-func (S *Scanner) scanChar() string {
+func (s *Scanner) scanChar() string {
        // '\'' opening already consumed
-       offs := S.offset - 1
+       offs := s.offset - 1
 
        n := 0
-       for S.ch != '\'' {
-               ch := S.ch
+       for s.ch != '\'' {
+               ch := s.ch
                n++
-               S.next()
+               s.next()
                if ch == '\n' || ch < 0 {
-                       S.error(offs, "character literal not terminated")
+                       s.error(offs, "character literal not terminated")
                        n = 1
                        break
                }
                if ch == '\\' {
-                       S.scanEscape('\'')
+                       s.scanEscape('\'')
                }
        }
 
-       S.next()
+       s.next()
 
        if n != 1 {
-               S.error(offs, "illegal character literal")
+               s.error(offs, "illegal character literal")
        }
 
-       return string(S.src[offs:S.offset])
+       return string(s.src[offs:s.offset])
 }
 
-func (S *Scanner) scanString() string {
+func (s *Scanner) scanString() string {
        // '"' opening already consumed
-       offs := S.offset - 1
+       offs := s.offset - 1
 
-       for S.ch != '"' {
-               ch := S.ch
-               S.next()
+       for s.ch != '"' {
+               ch := s.ch
+               s.next()
                if ch == '\n' || ch < 0 {
-                       S.error(offs, "string not terminated")
+                       s.error(offs, "string not terminated")
                        break
                }
                if ch == '\\' {
-                       S.scanEscape('"')
+                       s.scanEscape('"')
                }
        }
 
-       S.next()
+       s.next()
 
-       return string(S.src[offs:S.offset])
+       return string(s.src[offs:s.offset])
 }
 
 func stripCR(b []byte) []byte {
@@ -449,26 +449,26 @@ func stripCR(b []byte) []byte {
        return c[:i]
 }
 
-func (S *Scanner) scanRawString() string {
+func (s *Scanner) scanRawString() string {
        // '`' opening already consumed
-       offs := S.offset - 1
+       offs := s.offset - 1
 
        hasCR := false
-       for S.ch != '`' {
-               ch := S.ch
-               S.next()
+       for s.ch != '`' {
+               ch := s.ch
+               s.next()
                if ch == '\r' {
                        hasCR = true
                }
                if ch < 0 {
-                       S.error(offs, "string not terminated")
+                       s.error(offs, "string not terminated")
                        break
                }
        }
 
-       S.next()
+       s.next()
 
-       lit := S.src[offs:S.offset]
+       lit := s.src[offs:s.offset]
        if hasCR {
                lit = stripCR(lit)
        }
@@ -476,9 +476,9 @@ func (S *Scanner) scanRawString() string {
        return string(lit)
 }
 
-func (S *Scanner) skipWhitespace() {
-       for S.ch == ' ' || S.ch == '\t' || S.ch == '\n' && !S.insertSemi || S.ch == '\r' {
-               S.next()
+func (s *Scanner) skipWhitespace() {
+       for s.ch == ' ' || s.ch == '\t' || s.ch == '\n' && !s.insertSemi || s.ch == '\r' {
+               s.next()
        }
 }
 
@@ -488,35 +488,35 @@ func (S *Scanner) skipWhitespace() {
 // respectively. Otherwise, the result is tok0 if there was no other
 // matching character, or tok2 if the matching character was ch2.
 
-func (S *Scanner) switch2(tok0, tok1 token.Token) token.Token {
-       if S.ch == '=' {
-               S.next()
+func (s *Scanner) switch2(tok0, tok1 token.Token) token.Token {
+       if s.ch == '=' {
+               s.next()
                return tok1
        }
        return tok0
 }
 
-func (S *Scanner) switch3(tok0, tok1 token.Token, ch2 rune, tok2 token.Token) token.Token {
-       if S.ch == '=' {
-               S.next()
+func (s *Scanner) switch3(tok0, tok1 token.Token, ch2 rune, tok2 token.Token) token.Token {
+       if s.ch == '=' {
+               s.next()
                return tok1
        }
-       if S.ch == ch2 {
-               S.next()
+       if s.ch == ch2 {
+               s.next()
                return tok2
        }
        return tok0
 }
 
-func (S *Scanner) switch4(tok0, tok1 token.Token, ch2 rune, tok2, tok3 token.Token) token.Token {
-       if S.ch == '=' {
-               S.next()
+func (s *Scanner) switch4(tok0, tok1 token.Token, ch2 rune, tok2, tok3 token.Token) token.Token {
+       if s.ch == '=' {
+               s.next()
                return tok1
        }
-       if S.ch == ch2 {
-               S.next()
-               if S.ch == '=' {
-                       S.next()
+       if s.ch == ch2 {
+               s.next()
+               if s.ch == '=' {
+                       s.next()
                        return tok3
                }
                return tok2
@@ -553,18 +553,18 @@ func (S *Scanner) switch4(tok0, tok1 token.Token, ch2 rune, tok2, tok3 token.Tok
 // set with Init. Token positions are relative to that file
 // and thus relative to the file set.
 //
-func (S *Scanner) Scan() (pos token.Pos, tok token.Token, lit string) {
+func (s *Scanner) Scan() (pos token.Pos, tok token.Token, lit string) {
 scanAgain:
-       S.skipWhitespace()
+       s.skipWhitespace()
 
        // current token start
-       pos = S.file.Pos(S.offset)
+       pos = s.file.Pos(s.offset)
 
        // determine token value
        insertSemi := false
-       switch ch := S.ch; {
+       switch ch := s.ch; {
        case isLetter(ch):
-               lit = S.scanIdentifier()
+               lit = s.scanIdentifier()
                tok = token.Lookup(lit)
                switch tok {
                case token.IDENT, token.BREAK, token.CONTINUE, token.FALLTHROUGH, token.RETURN:
@@ -572,44 +572,44 @@ scanAgain:
                }
        case digitVal(ch) < 10:
                insertSemi = true
-               tok, lit = S.scanNumber(false)
+               tok, lit = s.scanNumber(false)
        default:
-               S.next() // always make progress
+               s.next() // always make progress
                switch ch {
                case -1:
-                       if S.insertSemi {
-                               S.insertSemi = false // EOF consumed
+                       if s.insertSemi {
+                               s.insertSemi = false // EOF consumed
                                return pos, token.SEMICOLON, "\n"
                        }
                        tok = token.EOF
                case '\n':
-                       // we only reach here if S.insertSemi was
+                       // we only reach here if s.insertSemi was
                        // set in the first place and exited early
-                       // from S.skipWhitespace()
-                       S.insertSemi = false // newline consumed
+                       // from s.skipWhitespace()
+                       s.insertSemi = false // newline consumed
                        return pos, token.SEMICOLON, "\n"
                case '"':
                        insertSemi = true
                        tok = token.STRING
-                       lit = S.scanString()
+                       lit = s.scanString()
                case '\'':
                        insertSemi = true
                        tok = token.CHAR
-                       lit = S.scanChar()
+                       lit = s.scanChar()
                case '`':
                        insertSemi = true
                        tok = token.STRING
-                       lit = S.scanRawString()
+                       lit = s.scanRawString()
                case ':':
-                       tok = S.switch2(token.COLON, token.DEFINE)
+                       tok = s.switch2(token.COLON, token.DEFINE)
                case '.':
-                       if digitVal(S.ch) < 10 {
+                       if digitVal(s.ch) < 10 {
                                insertSemi = true
-                               tok, lit = S.scanNumber(true)
-                       } else if S.ch == '.' {
-                               S.next()
-                               if S.ch == '.' {
-                                       S.next()
+                               tok, lit = s.scanNumber(true)
+                       } else if s.ch == '.' {
+                               s.next()
+                               if s.ch == '.' {
+                                       s.next()
                                        tok = token.ELLIPSIS
                                }
                        } else {
@@ -636,73 +636,73 @@ scanAgain:
                        insertSemi = true
                        tok = token.RBRACE
                case '+':
-                       tok = S.switch3(token.ADD, token.ADD_ASSIGN, '+', token.INC)
+                       tok = s.switch3(token.ADD, token.ADD_ASSIGN, '+', token.INC)
                        if tok == token.INC {
                                insertSemi = true
                        }
                case '-':
-                       tok = S.switch3(token.SUB, token.SUB_ASSIGN, '-', token.DEC)
+                       tok = s.switch3(token.SUB, token.SUB_ASSIGN, '-', token.DEC)
                        if tok == token.DEC {
                                insertSemi = true
                        }
                case '*':
-                       tok = S.switch2(token.MUL, token.MUL_ASSIGN)
+                       tok = s.switch2(token.MUL, token.MUL_ASSIGN)
                case '/':
-                       if S.ch == '/' || S.ch == '*' {
+                       if s.ch == '/' || s.ch == '*' {
                                // comment
-                               if S.insertSemi && S.findLineEnd() {
+                               if s.insertSemi && s.findLineEnd() {
                                        // reset position to the beginning of the comment
-                                       S.ch = '/'
-                                       S.offset = S.file.Offset(pos)
-                                       S.rdOffset = S.offset + 1
-                                       S.insertSemi = false // newline consumed
+                                       s.ch = '/'
+                                       s.offset = s.file.Offset(pos)
+                                       s.rdOffset = s.offset + 1
+                                       s.insertSemi = false // newline consumed
                                        return pos, token.SEMICOLON, "\n"
                                }
-                               lit = S.scanComment()
-                               if S.mode&ScanComments == 0 {
+                               lit = s.scanComment()
+                               if s.mode&ScanComments == 0 {
                                        // skip comment
-                                       S.insertSemi = false // newline consumed
+                                       s.insertSemi = false // newline consumed
                                        goto scanAgain
                                }
                                tok = token.COMMENT
                        } else {
-                               tok = S.switch2(token.QUO, token.QUO_ASSIGN)
+                               tok = s.switch2(token.QUO, token.QUO_ASSIGN)
                        }
                case '%':
-                       tok = S.switch2(token.REM, token.REM_ASSIGN)
+                       tok = s.switch2(token.REM, token.REM_ASSIGN)
                case '^':
-                       tok = S.switch2(token.XOR, token.XOR_ASSIGN)
+                       tok = s.switch2(token.XOR, token.XOR_ASSIGN)
                case '<':
-                       if S.ch == '-' {
-                               S.next()
+                       if s.ch == '-' {
+                               s.next()
                                tok = token.ARROW
                        } else {
-                               tok = S.switch4(token.LSS, token.LEQ, '<', token.SHL, token.SHL_ASSIGN)
+                               tok = s.switch4(token.LSS, token.LEQ, '<', token.SHL, token.SHL_ASSIGN)
                        }
                case '>':
-                       tok = S.switch4(token.GTR, token.GEQ, '>', token.SHR, token.SHR_ASSIGN)
+                       tok = s.switch4(token.GTR, token.GEQ, '>', token.SHR, token.SHR_ASSIGN)
                case '=':
-                       tok = S.switch2(token.ASSIGN, token.EQL)
+                       tok = s.switch2(token.ASSIGN, token.EQL)
                case '!':
-                       tok = S.switch2(token.NOT, token.NEQ)
+                       tok = s.switch2(token.NOT, token.NEQ)
                case '&':
-                       if S.ch == '^' {
-                               S.next()
-                               tok = S.switch2(token.AND_NOT, token.AND_NOT_ASSIGN)
+                       if s.ch == '^' {
+                               s.next()
+                               tok = s.switch2(token.AND_NOT, token.AND_NOT_ASSIGN)
                        } else {
-                               tok = S.switch3(token.AND, token.AND_ASSIGN, '&', token.LAND)
+                               tok = s.switch3(token.AND, token.AND_ASSIGN, '&', token.LAND)
                        }
                case '|':
-                       tok = S.switch3(token.OR, token.OR_ASSIGN, '|', token.LOR)
+                       tok = s.switch3(token.OR, token.OR_ASSIGN, '|', token.LOR)
                default:
-                       S.error(S.file.Offset(pos), fmt.Sprintf("illegal character %#U", ch))
-                       insertSemi = S.insertSemi // preserve insertSemi info
+                       s.error(s.file.Offset(pos), fmt.Sprintf("illegal character %#U", ch))
+                       insertSemi = s.insertSemi // preserve insertSemi info
                        tok = token.ILLEGAL
                        lit = string(ch)
                }
        }
-       if S.mode&dontInsertSemis == 0 {
-               S.insertSemi = insertSemi
+       if s.mode&dontInsertSemis == 0 {
+               s.insertSemi = insertSemi
        }
 
        return
index af45bc5b1c8af8788a4275c07a97def3fd573867..e7f7cd1c1e9af43655a9cb32ef3bed8b77025780 100644 (file)
@@ -230,7 +230,13 @@ func TestScan(t *testing.T) {
        var s Scanner
        s.Init(fset.AddFile("", fset.Base(), len(source)), source, &testErrorHandler{t}, ScanComments|dontInsertSemis)
        index := 0
-       epos := token.Position{"", 0, 1, 1} // expected position
+       // epos is the expected position
+       epos := token.Position{
+               Filename: "",
+               Offset:   0,
+               Line:     1,
+               Column:   1,
+       }
        for {
                pos, tok, lit := s.Scan()
                if lit == "" {
@@ -505,7 +511,12 @@ func TestLineComments(t *testing.T) {
        for _, s := range segs {
                p, _, lit := S.Scan()
                pos := file.Position(p)
-               checkPos(t, lit, p, token.Position{s.filename, pos.Offset, s.line, pos.Column})
+               checkPos(t, lit, p, token.Position{
+                       Filename: s.filename,
+                       Offset:   pos.Offset,
+                       Line:     s.line,
+                       Column:   pos.Column,
+               })
        }
 
        if S.ErrorCount != 0 {
index 042d6abdf9d236db8ee759ad448e339e63dc36ff..4adc8f9e33422f656039c98a50c65713b3734698 100644 (file)
@@ -4,11 +4,6 @@
 
 package token
 
-import (
-       "encoding/gob"
-       "io"
-)
-
 type serializedFile struct {
        // fields correspond 1:1 to fields with same (lower-case) name in File
        Name  string
@@ -23,19 +18,10 @@ type serializedFileSet struct {
        Files []serializedFile
 }
 
-func (s *serializedFileSet) Read(r io.Reader) error {
-       return gob.NewDecoder(r).Decode(s)
-}
-
-func (s *serializedFileSet) Write(w io.Writer) error {
-       return gob.NewEncoder(w).Encode(s)
-}
-
-// Read reads the fileset from r into s; s must not be nil.
-// If r does not also implement io.ByteReader, it will be wrapped in a bufio.Reader.
-func (s *FileSet) Read(r io.Reader) error {
+// Read calls decode to deserialize a file set into s; s must not be nil.
+func (s *FileSet) Read(decode func(interface{}) error) error {
        var ss serializedFileSet
-       if err := ss.Read(r); err != nil {
+       if err := decode(&ss); err != nil {
                return err
        }
 
@@ -53,8 +39,8 @@ func (s *FileSet) Read(r io.Reader) error {
        return nil
 }
 
-// Write writes the fileset s to w.
-func (s *FileSet) Write(w io.Writer) error {
+// Write calls encode to serialize the file set s.
+func (s *FileSet) Write(encode func(interface{}) error) error {
        var ss serializedFileSet
 
        s.mutex.Lock()
@@ -66,5 +52,5 @@ func (s *FileSet) Write(w io.Writer) error {
        ss.Files = files
        s.mutex.Unlock()
 
-       return ss.Write(w)
+       return encode(ss)
 }
index a8ce30ab2f380a986a994f61d57164e9d4fed5ac..4e925adb6f26406df05ae62582ab866e1b95c8be 100644 (file)
@@ -6,6 +6,7 @@ package token
 
 import (
        "bytes"
+       "encoding/gob"
        "fmt"
        "testing"
 )
@@ -69,12 +70,18 @@ func equal(p, q *FileSet) error {
 
 func checkSerialize(t *testing.T, p *FileSet) {
        var buf bytes.Buffer
-       if err := p.Write(&buf); err != nil {
+       encode := func(x interface{}) error {
+               return gob.NewEncoder(&buf).Encode(x)
+       }
+       if err := p.Write(encode); err != nil {
                t.Errorf("writing fileset failed: %s", err)
                return
        }
        q := NewFileSet()
-       if err := q.Read(&buf); err != nil {
+       decode := func(x interface{}) error {
+               return gob.NewDecoder(&buf).Decode(x)
+       }
+       if err := q.Read(decode); err != nil {
                t.Errorf("reading fileset failed: %s", err)
                return
        }
index c0b5262af83a712ba572982a3daaa8ab6607dd87..fee771a5784e200eb47d42072ebb463e78aaaef9 100644 (file)
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// Package html provides functions for escaping and unescaping HTML text.
 package html
 
 import (
@@ -237,8 +238,8 @@ func EscapeString(s string) string {
        if strings.IndexAny(s, escapedChars) == -1 {
                return s
        }
-       buf := bytes.NewBuffer(nil)
-       escape(buf, s)
+       var buf bytes.Buffer
+       escape(&buf, s)
        return buf.String()
 }
 
index 0e31674f05fd1b38e42565501ac3b3387f3206e9..70cada3f50b07a62258bf3d39e04f1ab674d7e92 100644 (file)
@@ -1471,7 +1471,7 @@ func TestEscapeText(t *testing.T) {
 
        for _, test := range tests {
                b, e := []byte(test.input), newEscaper(nil)
-               c := e.escapeText(context{}, &parse.TextNode{parse.NodeText, b})
+               c := e.escapeText(context{}, &parse.TextNode{NodeType: parse.NodeText, Text: b})
                if !test.output.eq(c) {
                        t.Errorf("input %q: want context\n\t%v\ngot\n\t%v", test.input, test.output, c)
                        continue
index 0e632df42201e49661f98d0671069e2b4bcb155e..a895a50aa9025da8b72482ad9045d84fb5a52e67 100644 (file)
@@ -154,7 +154,7 @@ func jsValEscaper(args ...interface{}) string {
                a = fmt.Sprint(args...)
        }
        // TODO: detect cycles before calling Marshal which loops infinitely on
-       // cyclic data. This may be an unnacceptable DoS risk.
+       // cyclic data. This may be an unacceptable DoS risk.
 
        b, err := json.Marshal(a)
        if err != nil {
diff --git a/libgo/go/image/bmp/reader.go b/libgo/go/image/bmp/reader.go
deleted file mode 100644 (file)
index 58bd781..0000000
+++ /dev/null
@@ -1,152 +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 bmp implements a BMP image decoder.
-//
-// The BMP specification is at http://www.digicamsoft.com/bmp/bmp.html.
-package bmp
-
-import (
-       "errors"
-       "image"
-       "image/color"
-       "io"
-)
-
-// ErrUnsupported means that the input BMP image uses a valid but unsupported
-// feature.
-var ErrUnsupported = errors.New("bmp: unsupported BMP image")
-
-func readUint16(b []byte) uint16 {
-       return uint16(b[0]) | uint16(b[1])<<8
-}
-
-func readUint32(b []byte) uint32 {
-       return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
-}
-
-// decodePaletted reads an 8 bit-per-pixel BMP image from r.
-func decodePaletted(r io.Reader, c image.Config) (image.Image, error) {
-       var tmp [4]byte
-       paletted := image.NewPaletted(image.Rect(0, 0, c.Width, c.Height), c.ColorModel.(color.Palette))
-       // BMP images are stored bottom-up rather than top-down.
-       for y := c.Height - 1; y >= 0; y-- {
-               p := paletted.Pix[y*paletted.Stride : y*paletted.Stride+c.Width]
-               _, err := io.ReadFull(r, p)
-               if err != nil {
-                       return nil, err
-               }
-               // Each row is 4-byte aligned.
-               if c.Width%4 != 0 {
-                       _, err := io.ReadFull(r, tmp[:4-c.Width%4])
-                       if err != nil {
-                               return nil, err
-                       }
-               }
-       }
-       return paletted, nil
-}
-
-// decodeRGBA reads a 24 bit-per-pixel BMP image from r.
-func decodeRGBA(r io.Reader, c image.Config) (image.Image, error) {
-       rgba := image.NewRGBA(image.Rect(0, 0, c.Width, c.Height))
-       // There are 3 bytes per pixel, and each row is 4-byte aligned.
-       b := make([]byte, (3*c.Width+3)&^3)
-       // BMP images are stored bottom-up rather than top-down.
-       for y := c.Height - 1; y >= 0; y-- {
-               _, err := io.ReadFull(r, b)
-               if err != nil {
-                       return nil, err
-               }
-               p := rgba.Pix[y*rgba.Stride : y*rgba.Stride+c.Width*4]
-               for i, j := 0, 0; i < len(p); i, j = i+4, j+3 {
-                       // BMP images are stored in BGR order rather than RGB order.
-                       p[i+0] = b[j+2]
-                       p[i+1] = b[j+1]
-                       p[i+2] = b[j+0]
-                       p[i+3] = 0xFF
-               }
-       }
-       return rgba, nil
-}
-
-// Decode reads a BMP image from r and returns it as an image.Image.
-// Limitation: The file must be 8 or 24 bits per pixel.
-func Decode(r io.Reader) (image.Image, error) {
-       c, err := DecodeConfig(r)
-       if err != nil {
-               return nil, err
-       }
-       if c.ColorModel == color.RGBAModel {
-               return decodeRGBA(r, c)
-       }
-       return decodePaletted(r, c)
-}
-
-// DecodeConfig returns the color model and dimensions of a BMP image without
-// decoding the entire image.
-// Limitation: The file must be 8 or 24 bits per pixel.
-func DecodeConfig(r io.Reader) (config image.Config, err error) {
-       // We only support those BMP images that are a BITMAPFILEHEADER
-       // immediately followed by a BITMAPINFOHEADER.
-       const (
-               fileHeaderLen = 14
-               infoHeaderLen = 40
-       )
-       var b [1024]byte
-       if _, err = io.ReadFull(r, b[:fileHeaderLen+infoHeaderLen]); err != nil {
-               return
-       }
-       if string(b[:2]) != "BM" {
-               err = errors.New("bmp: invalid format")
-               return
-       }
-       offset := readUint32(b[10:14])
-       if readUint32(b[14:18]) != infoHeaderLen {
-               err = ErrUnsupported
-               return
-       }
-       width := int(readUint32(b[18:22]))
-       height := int(readUint32(b[22:26]))
-       if width < 0 || height < 0 {
-               err = ErrUnsupported
-               return
-       }
-       // We only support 1 plane, 8 or 24 bits per pixel and no compression.
-       planes, bpp, compression := readUint16(b[26:28]), readUint16(b[28:30]), readUint32(b[30:34])
-       if planes != 1 || compression != 0 {
-               err = ErrUnsupported
-               return
-       }
-       switch bpp {
-       case 8:
-               if offset != fileHeaderLen+infoHeaderLen+256*4 {
-                       err = ErrUnsupported
-                       return
-               }
-               _, err = io.ReadFull(r, b[:256*4])
-               if err != nil {
-                       return
-               }
-               pcm := make(color.Palette, 256)
-               for i := range pcm {
-                       // BMP images are stored in BGR order rather than RGB order.
-                       // Every 4th byte is padding.
-                       pcm[i] = color.RGBA{b[4*i+2], b[4*i+1], b[4*i+0], 0xFF}
-               }
-               return image.Config{pcm, width, height}, nil
-       case 24:
-               if offset != fileHeaderLen+infoHeaderLen {
-                       err = ErrUnsupported
-                       return
-               }
-               return image.Config{color.RGBAModel, width, height}, nil
-       }
-       err = ErrUnsupported
-       return
-}
-
-func init() {
-       image.RegisterFormat("bmp", "BM????\x00\x00\x00\x00", Decode, DecodeConfig)
-}
index 1b7db8bade4a68feadc37661abeea916f3fa1111..d659867243fbc0b3cdd93e27061bca774434f165 100644 (file)
@@ -11,11 +11,9 @@ import (
        "os"
        "testing"
 
-       _ "image/bmp"
        _ "image/gif"
        _ "image/jpeg"
        _ "image/png"
-       _ "image/tiff"
 )
 
 type imageTest struct {
@@ -25,7 +23,7 @@ type imageTest struct {
 }
 
 var imageTests = []imageTest{
-       {"testdata/video-001.png", "testdata/video-001.bmp", 0},
+       {"testdata/video-001.png", "testdata/video-001.png", 0},
        // GIF images are restricted to a 256-color palette and the conversion
        // to GIF loses significant image quality.
        {"testdata/video-001.png", "testdata/video-001.gif", 64 << 8},
@@ -33,10 +31,7 @@ var imageTests = []imageTest{
        {"testdata/video-001.png", "testdata/video-001.5bpp.gif", 128 << 8},
        // JPEG is a lossy format and hence needs a non-zero tolerance.
        {"testdata/video-001.png", "testdata/video-001.jpeg", 8 << 8},
-       {"testdata/video-001.png", "testdata/video-001.png", 0},
-       {"testdata/video-001.png", "testdata/video-001.tiff", 0},
-
-       // Test grayscale images.
+       // Grayscale images.
        {"testdata/video-005.gray.png", "testdata/video-005.gray.jpeg", 8 << 8},
        {"testdata/video-005.gray.png", "testdata/video-005.gray.png", 0},
 }
index 4cd2095c441195678f5be74c07e8a4f6e5432ae4..cc62e25f1bbfcedfdacca70f464aa9796c2d24b0 100644 (file)
@@ -56,7 +56,7 @@ func bench(b *testing.B, dcm, scm, mcm color.Model, op Op) {
        var src image.Image
        switch scm {
        case nil:
-               src = &image.Uniform{color.RGBA{0x11, 0x22, 0x33, 0xff}}
+               src = &image.Uniform{C: color.RGBA{0x11, 0x22, 0x33, 0xff}}
        case color.RGBAModel:
                src1 := image.NewRGBA(image.Rect(0, 0, srcw, srch))
                for y := 0; y < srch; y++ {
@@ -145,7 +145,7 @@ func bench(b *testing.B, dcm, scm, mcm color.Model, op Op) {
                x := 3 * i % (dstw - srcw)
                y := 7 * i % (dsth - srch)
 
-               DrawMask(dst, dst.Bounds().Add(image.Point{x, y}), src, image.ZP, mask, image.ZP, op)
+               DrawMask(dst, dst.Bounds().Add(image.Pt(x, y)), src, image.ZP, mask, image.ZP, op)
        }
 }
 
index 56a45026b57ca46d6f362bc68db03d186ad1d3b3..1db75b3e3f63ad28ec92249915c64c700ecc360f 100644 (file)
@@ -168,15 +168,15 @@ func makeGolden(dst image.Image, r image.Rectangle, src image.Image, sp image.Po
                sy := y + sp.Y - r.Min.Y
                my := y + mp.Y - r.Min.Y
                for x := r.Min.X; x < r.Max.X; x++ {
-                       if !(image.Point{x, y}.In(b)) {
+                       if !(image.Pt(x, y).In(b)) {
                                continue
                        }
                        sx := x + sp.X - r.Min.X
-                       if !(image.Point{sx, sy}.In(sb)) {
+                       if !(image.Pt(sx, sy).In(sb)) {
                                continue
                        }
                        mx := x + mp.X - r.Min.X
-                       if !(image.Point{mx, my}.In(mb)) {
+                       if !(image.Pt(mx, my).In(mb)) {
                                continue
                        }
 
@@ -313,7 +313,7 @@ func TestFill(t *testing.T) {
                m := image.NewRGBA(image.Rect(0, 0, 40, 30)).SubImage(r).(*image.RGBA)
                b := m.Bounds()
                c := color.RGBA{11, 0, 0, 255}
-               src := &image.Uniform{c}
+               src := &image.Uniform{C: c}
                check := func(desc string) {
                        for y := b.Min.Y; y < b.Max.Y; y++ {
                                for x := b.Min.X; x < b.Max.X; x++ {
@@ -333,21 +333,21 @@ func TestFill(t *testing.T) {
                check("pixel")
                // Draw 1 row at a time.
                c = color.RGBA{0, 22, 0, 255}
-               src = &image.Uniform{c}
+               src = &image.Uniform{C: c}
                for y := b.Min.Y; y < b.Max.Y; y++ {
                        DrawMask(m, image.Rect(b.Min.X, y, b.Max.X, y+1), src, image.ZP, nil, image.ZP, Src)
                }
                check("row")
                // Draw 1 column at a time.
                c = color.RGBA{0, 0, 33, 255}
-               src = &image.Uniform{c}
+               src = &image.Uniform{C: c}
                for x := b.Min.X; x < b.Max.X; x++ {
                        DrawMask(m, image.Rect(x, b.Min.Y, x+1, b.Max.Y), src, image.ZP, nil, image.ZP, Src)
                }
                check("column")
                // Draw the whole image at once.
                c = color.RGBA{44, 55, 66, 77}
-               src = &image.Uniform{c}
+               src = &image.Uniform{C: c}
                DrawMask(m, b, src, image.ZP, nil, image.ZP, Src)
                check("whole")
        }
index 78fc3ed619fa07ffee1c18934b3ed74e8b989376..f93d356b041465d85f0a37fdd9b34003ee9842e2 100644 (file)
@@ -10,8 +10,8 @@ import (
        "io"
 )
 
-// An UnknownFormatErr indicates that decoding encountered an unknown format.
-var UnknownFormatErr = errors.New("image: unknown format")
+// ErrFormat indicates that decoding encountered an unknown format.
+var ErrFormat = errors.New("image: unknown format")
 
 // A format holds an image format's name, magic header and how to decode it.
 type format struct {
@@ -79,7 +79,7 @@ func Decode(r io.Reader) (Image, string, error) {
        rr := asReader(r)
        f := sniff(rr)
        if f.decode == nil {
-               return nil, "", UnknownFormatErr
+               return nil, "", ErrFormat
        }
        m, err := f.decode(rr)
        return m, f.name, err
@@ -93,7 +93,7 @@ func DecodeConfig(r io.Reader) (Config, string, error) {
        rr := asReader(r)
        f := sniff(rr)
        if f.decodeConfig == nil {
-               return Config{}, "", UnknownFormatErr
+               return Config{}, "", ErrFormat
        }
        c, err := f.decodeConfig(rr)
        return c, f.name, err
index 24b53c5b0a91a09d9f0304983f6d17a22cfdfd96..8b36948d6993b9bbd84fcfd8ce16bbc96f5196bc 100644 (file)
@@ -416,7 +416,11 @@ func DecodeConfig(r io.Reader) (image.Config, error) {
        if err := d.decode(r, true); err != nil {
                return image.Config{}, err
        }
-       return image.Config{d.globalColorMap, d.width, d.height}, nil
+       return image.Config{
+               ColorModel: d.globalColorMap,
+               Width:      d.width,
+               Height:     d.height,
+       }, nil
 }
 
 func init() {
index 9dd676aceddfb720e1a2076e9711083d06fa731e..63bfb7d59e40c58c3055b84a35407c03cea7e562 100644 (file)
@@ -4,7 +4,20 @@
 
 // Package image implements a basic 2-D image library.
 //
-// See "The Go image package" for an introduction to this package:
+// The fundamental interface is called Image. An Image contains colors, which
+// are described in the image/color package.
+//
+// Values of the Image interface are created either by calling functions such
+// as NewRGBA and NewPaletted, or by calling Decode on an io.Reader containing
+// image data in a format such as GIF, JPEG or PNG. Decoding any particular
+// image format requires the prior registration of a decoder function.
+// Registration is typically automatic as a side effect of initializing that
+// format's package so that, to decode a PNG image, it suffices to have
+//     import _ "image/png"
+// in a program's main package. The _ means to import a package purely for its
+// initialization side effects.
+//
+// See "The Go image package" for more details:
 // http://blog.golang.org/2011/09/go-image-package.html
 package image
 
@@ -18,7 +31,8 @@ type Config struct {
        Width, Height int
 }
 
-// Image is a finite rectangular grid of Colors drawn from a color model.
+// Image is a finite rectangular grid of color.Color values taken from a color
+// model.
 type Image interface {
        // ColorModel returns the Image's color model.
        ColorModel() color.Model
@@ -42,7 +56,7 @@ type PalettedImage interface {
        Image
 }
 
-// RGBA is an in-memory image of RGBAColor values.
+// RGBA is an in-memory image whose At method returns color.RGBA values.
 type RGBA struct {
        // Pix holds the image's pixels, in R, G, B, A order. The pixel at
        // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4].
@@ -137,7 +151,7 @@ func NewRGBA(r Rectangle) *RGBA {
        return &RGBA{buf, 4 * w, r}
 }
 
-// RGBA64 is an in-memory image of RGBA64Color values.
+// RGBA64 is an in-memory image whose At method returns color.RGBA64 values.
 type RGBA64 struct {
        // Pix holds the image's pixels, in R, G, B, A order and big-endian format. The pixel at
        // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*8].
@@ -245,7 +259,7 @@ func NewRGBA64(r Rectangle) *RGBA64 {
        return &RGBA64{pix, 8 * w, r}
 }
 
-// NRGBA is an in-memory image of NRGBAColor values.
+// NRGBA is an in-memory image whose At method returns color.NRGBA values.
 type NRGBA struct {
        // Pix holds the image's pixels, in R, G, B, A order. The pixel at
        // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4].
@@ -340,7 +354,7 @@ func NewNRGBA(r Rectangle) *NRGBA {
        return &NRGBA{pix, 4 * w, r}
 }
 
-// NRGBA64 is an in-memory image of NRGBA64Color values.
+// NRGBA64 is an in-memory image whose At method returns color.NRGBA64 values.
 type NRGBA64 struct {
        // Pix holds the image's pixels, in R, G, B, A order and big-endian format. The pixel at
        // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*8].
@@ -448,7 +462,7 @@ func NewNRGBA64(r Rectangle) *NRGBA64 {
        return &NRGBA64{pix, 8 * w, r}
 }
 
-// Alpha is an in-memory image of AlphaColor values.
+// Alpha is an in-memory image whose At method returns color.Alpha values.
 type Alpha struct {
        // Pix holds the image's pixels, as alpha values. The pixel at
        // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1].
@@ -536,7 +550,7 @@ func NewAlpha(r Rectangle) *Alpha {
        return &Alpha{pix, 1 * w, r}
 }
 
-// Alpha16 is an in-memory image of Alpha16Color values.
+// Alpha16 is an in-memory image whose At method returns color.Alpha64 values.
 type Alpha16 struct {
        // Pix holds the image's pixels, as alpha values in big-endian format. The pixel at
        // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*2].
@@ -627,7 +641,7 @@ func NewAlpha16(r Rectangle) *Alpha16 {
        return &Alpha16{pix, 2 * w, r}
 }
 
-// Gray is an in-memory image of GrayColor values.
+// Gray is an in-memory image whose At method returns color.Gray values.
 type Gray struct {
        // Pix holds the image's pixels, as gray values. The pixel at
        // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*1].
@@ -702,7 +716,7 @@ func NewGray(r Rectangle) *Gray {
        return &Gray{pix, 1 * w, r}
 }
 
-// Gray16 is an in-memory image of Gray16Color values.
+// Gray16 is an in-memory image whose At method returns color.Gray16 values.
 type Gray16 struct {
        // Pix holds the image's pixels, as gray values in big-endian format. The pixel at
        // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*2].
index 2e412ad171626a399f7bb91338bc6053c3509574..d9adf6e587627b89f7902c81fa00fe2ba5f4a663 100644 (file)
@@ -454,9 +454,17 @@ func DecodeConfig(r io.Reader) (image.Config, error) {
        }
        switch d.nComp {
        case nGrayComponent:
-               return image.Config{color.GrayModel, d.width, d.height}, nil
+               return image.Config{
+                       ColorModel: color.GrayModel,
+                       Width:      d.width,
+                       Height:     d.height,
+               }, nil
        case nColorComponent:
-               return image.Config{color.YCbCrModel, d.width, d.height}, nil
+               return image.Config{
+                       ColorModel: color.YCbCrModel,
+                       Width:      d.width,
+                       Height:     d.height,
+               }, nil
        }
        return image.Config{}, FormatError("missing SOF marker")
 }
index 71fe37ce7ffc3d87cdc1ffe9785a62b6dddc84a1..3322c09fe71a81ed685b6146e75082d6ed995ce4 100644 (file)
@@ -458,7 +458,7 @@ func (e *encoder) writeSOS(m image.Image) {
                        for i := 0; i < 4; i++ {
                                xOff := (i & 1) * 8
                                yOff := (i & 2) * 4
-                               p := image.Point{x + xOff, y + yOff}
+                               p := image.Pt(x+xOff, y+yOff)
                                if rgba != nil {
                                        rgbaToYCbCr(rgba, p, &yBlock, &cbBlock[i], &crBlock[i])
                                } else {
index e4b56d28847d517e7c9ea0eda7d19763623db55f..b8e8fa34e189ce97857f9e3c3a662a0b3288ded8 100644 (file)
@@ -54,14 +54,14 @@ func TestWriter(t *testing.T) {
                        continue
                }
                // Encode that image as JPEG.
-               buf := bytes.NewBuffer(nil)
-               err = Encode(buf, m0, &Options{Quality: tc.quality})
+               var buf bytes.Buffer
+               err = Encode(&buf, m0, &Options{Quality: tc.quality})
                if err != nil {
                        t.Error(tc.filename, err)
                        continue
                }
                // Decode that JPEG.
-               m1, err := Decode(buf)
+               m1, err := Decode(&buf)
                if err != nil {
                        t.Error(tc.filename, err)
                        continue
index b830f88e1c454cb760aedd0b954b888447a8408a..55f634c17c1d73af843418e1941c392756d18571 100644 (file)
@@ -50,26 +50,3 @@ func (c *Uniform) Opaque() bool {
 func NewUniform(c color.Color) *Uniform {
        return &Uniform{c}
 }
-
-// Repeated is an infinite-sized Image that repeats another Image in both
-// directions. Repeated{i, p}.At(x, y) will equal i.At(x+p.X, y+p.Y) for all
-// points {x+p.X, y+p.Y} within i's Bounds.
-type Repeated struct {
-       I      Image
-       Offset Point
-}
-
-func (r *Repeated) ColorModel() color.Model {
-       return r.I.ColorModel()
-}
-
-func (r *Repeated) Bounds() Rectangle { return Rectangle{Point{-1e9, -1e9}, Point{1e9, 1e9}} }
-
-func (r *Repeated) At(x, y int) color.Color {
-       p := Point{x, y}.Add(r.Offset).Mod(r.I.Bounds())
-       return r.I.At(p.X, p.Y)
-}
-
-func NewRepeated(i Image, offset Point) *Repeated {
-       return &Repeated{i, offset}
-}
index 7eb8cea9d567c6227b1a0db3803944f90232d5d5..fe07d60a91adc5635588467f803c114a4a78f062 100644 (file)
@@ -690,7 +690,11 @@ func DecodeConfig(r io.Reader) (image.Config, error) {
        case cbTCA16:
                cm = color.NRGBA64Model
        }
-       return image.Config{cm, d.width, d.height}, nil
+       return image.Config{
+               ColorModel: cm,
+               Width:      d.width,
+               Height:     d.height,
+       }, nil
 }
 
 func init() {
index 641eae1bb8e8c0cb88c1ecc7d8f2db4d05095fe4..286a3bc15db33393e0f8adb327671a78b191cf4c 100644 (file)
@@ -408,10 +408,7 @@ func (e *encoder) writeIDATs() {
                return
        }
        var bw *bufio.Writer
-       bw, e.err = bufio.NewWriterSize(e, 1<<15)
-       if e.err != nil {
-               return
-       }
+       bw = bufio.NewWriterSize(e, 1<<15)
        e.err = writeImage(bw, e.m, e.cb)
        if e.err != nil {
                return
index 228ecccfb4f76486457d7ab6b81847abcf22229f..644c4fb44b39a6a9fb4732213fae53f32dcf2d6a 100644 (file)
@@ -35,12 +35,12 @@ func diff(m0, m1 image.Image) error {
 }
 
 func encodeDecode(m image.Image) (image.Image, error) {
-       b := bytes.NewBuffer(nil)
-       err := Encode(b, m)
+       var b bytes.Buffer
+       err := Encode(&b, m)
        if err != nil {
                return nil, err
        }
-       m, err = Decode(b)
+       m, err = Decode(&b)
        if err != nil {
                return nil, err
        }
diff --git a/libgo/go/image/testdata/video-001.bmp b/libgo/go/image/testdata/video-001.bmp
deleted file mode 100644 (file)
index ca3dd42..0000000
Binary files a/libgo/go/image/testdata/video-001.bmp and /dev/null differ
diff --git a/libgo/go/image/testdata/video-001.tiff b/libgo/go/image/testdata/video-001.tiff
deleted file mode 100644 (file)
index 0dd6cd9..0000000
Binary files a/libgo/go/image/testdata/video-001.tiff and /dev/null differ
diff --git a/libgo/go/image/tiff/buffer.go b/libgo/go/image/tiff/buffer.go
deleted file mode 100644 (file)
index 27533c6..0000000
+++ /dev/null
@@ -1,54 +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 tiff
-
-import "io"
-
-// buffer buffers an io.Reader to satisfy io.ReaderAt.
-type buffer struct {
-       r   io.Reader
-       buf []byte
-}
-
-func (b *buffer) ReadAt(p []byte, off int64) (int, error) {
-       o := int(off)
-       end := o + len(p)
-       if int64(end) != off+int64(len(p)) {
-               return 0, io.ErrUnexpectedEOF
-       }
-
-       m := len(b.buf)
-       if end > m {
-               if end > cap(b.buf) {
-                       newcap := 1024
-                       for newcap < end {
-                               newcap *= 2
-                       }
-                       newbuf := make([]byte, end, newcap)
-                       copy(newbuf, b.buf)
-                       b.buf = newbuf
-               } else {
-                       b.buf = b.buf[:end]
-               }
-               if n, err := io.ReadFull(b.r, b.buf[m:end]); err != nil {
-                       end = m + n
-                       b.buf = b.buf[:end]
-                       return copy(p, b.buf[o:end]), err
-               }
-       }
-
-       return copy(p, b.buf[o:end]), nil
-}
-
-// newReaderAt converts an io.Reader into an io.ReaderAt.
-func newReaderAt(r io.Reader) io.ReaderAt {
-       if ra, ok := r.(io.ReaderAt); ok {
-               return ra
-       }
-       return &buffer{
-               r:   r,
-               buf: make([]byte, 0, 1024),
-       }
-}
diff --git a/libgo/go/image/tiff/buffer_test.go b/libgo/go/image/tiff/buffer_test.go
deleted file mode 100644 (file)
index e13afb3..0000000
+++ /dev/null
@@ -1,36 +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 tiff
-
-import (
-       "io"
-       "strings"
-       "testing"
-)
-
-var readAtTests = []struct {
-       n   int
-       off int64
-       s   string
-       err error
-}{
-       {2, 0, "ab", nil},
-       {6, 0, "abcdef", nil},
-       {3, 3, "def", nil},
-       {3, 5, "f", io.EOF},
-       {3, 6, "", io.EOF},
-}
-
-func TestReadAt(t *testing.T) {
-       r := newReaderAt(strings.NewReader("abcdef"))
-       b := make([]byte, 10)
-       for _, test := range readAtTests {
-               n, err := r.ReadAt(b[:test.n], test.off)
-               s := string(b[:n])
-               if s != test.s || err != test.err {
-                       t.Errorf("buffer.ReadAt(<%v bytes>, %v): got %v, %q; want %v, %q", test.n, test.off, err, s, test.err, test.s)
-               }
-       }
-}
diff --git a/libgo/go/image/tiff/compress.go b/libgo/go/image/tiff/compress.go
deleted file mode 100644 (file)
index 40c7fd8..0000000
+++ /dev/null
@@ -1,59 +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 tiff
-
-import (
-       "bufio"
-       "io"
-)
-
-type byteReader interface {
-       io.Reader
-       io.ByteReader
-}
-
-// unpackBits decodes the PackBits-compressed data in src and returns the
-// uncompressed data.
-//
-// The PackBits compression format is described in section 9 (p. 42)
-// of the TIFF spec.
-func unpackBits(r io.Reader) ([]byte, error) {
-       buf := make([]byte, 128)
-       dst := make([]byte, 0, 1024)
-       br, ok := r.(byteReader)
-       if !ok {
-               br = bufio.NewReader(r)
-       }
-
-       for {
-               b, err := br.ReadByte()
-               if err != nil {
-                       if err == io.EOF {
-                               return dst, nil
-                       }
-                       return nil, err
-               }
-               code := int(int8(b))
-               switch {
-               case code >= 0:
-                       n, err := io.ReadFull(br, buf[:code+1])
-                       if err != nil {
-                               return nil, err
-                       }
-                       dst = append(dst, buf[:n]...)
-               case code == -128:
-                       // No-op.
-               default:
-                       if b, err = br.ReadByte(); err != nil {
-                               return nil, err
-                       }
-                       for j := 0; j < 1-code; j++ {
-                               buf[j] = b
-                       }
-                       dst = append(dst, buf[:1-code]...)
-               }
-       }
-       panic("unreachable")
-}
diff --git a/libgo/go/image/tiff/consts.go b/libgo/go/image/tiff/consts.go
deleted file mode 100644 (file)
index 169ba27..0000000
+++ /dev/null
@@ -1,103 +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 tiff
-
-// A tiff image file contains one or more images. The metadata
-// of each image is contained in an Image File Directory (IFD),
-// which contains entries of 12 bytes each and is described
-// on page 14-16 of the specification. An IFD entry consists of
-//
-//  - a tag, which describes the signification of the entry,
-//  - the data type and length of the entry,
-//  - the data itself or a pointer to it if it is more than 4 bytes.
-//
-// The presence of a length means that each IFD is effectively an array.
-
-const (
-       leHeader = "II\x2A\x00" // Header for little-endian files.
-       beHeader = "MM\x00\x2A" // Header for big-endian files.
-
-       ifdLen = 12 // Length of an IFD entry in bytes.
-)
-
-// Data types (p. 14-16 of the spec).
-const (
-       dtByte     = 1
-       dtASCII    = 2
-       dtShort    = 3
-       dtLong     = 4
-       dtRational = 5
-)
-
-// The length of one instance of each data type in bytes.
-var lengths = [...]uint32{0, 1, 1, 2, 4, 8}
-
-// Tags (see p. 28-41 of the spec).
-const (
-       tImageWidth                = 256
-       tImageLength               = 257
-       tBitsPerSample             = 258
-       tCompression               = 259
-       tPhotometricInterpretation = 262
-
-       tStripOffsets    = 273
-       tSamplesPerPixel = 277
-       tRowsPerStrip    = 278
-       tStripByteCounts = 279
-
-       tXResolution    = 282
-       tYResolution    = 283
-       tResolutionUnit = 296
-
-       tPredictor    = 317
-       tColorMap     = 320
-       tExtraSamples = 338
-       tSampleFormat = 339
-)
-
-// Compression types (defined in various places in the spec and supplements).
-const (
-       cNone       = 1
-       cCCITT      = 2
-       cG3         = 3 // Group 3 Fax.
-       cG4         = 4 // Group 4 Fax.
-       cLZW        = 5
-       cJPEGOld    = 6 // Superseded by cJPEG.
-       cJPEG       = 7
-       cDeflate    = 8 // zlib compression.
-       cPackBits   = 32773
-       cDeflateOld = 32946 // Superseded by cDeflate.
-)
-
-// Photometric interpretation values (see p. 37 of the spec).
-const (
-       pWhiteIsZero = 0
-       pBlackIsZero = 1
-       pRGB         = 2
-       pPaletted    = 3
-       pTransMask   = 4 // transparency mask
-       pCMYK        = 5
-       pYCbCr       = 6
-       pCIELab      = 8
-)
-
-// Values for the tPredictor tag (page 64-65 of the spec).
-const (
-       prNone       = 1
-       prHorizontal = 2
-)
-
-// imageMode represents the mode of the image.
-type imageMode int
-
-const (
-       mBilevel imageMode = iota
-       mPaletted
-       mGray
-       mGrayInvert
-       mRGB
-       mRGBA
-       mNRGBA
-)
diff --git a/libgo/go/image/tiff/reader.go b/libgo/go/image/tiff/reader.go
deleted file mode 100644 (file)
index dc5a87a..0000000
+++ /dev/null
@@ -1,430 +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 tiff implements a TIFF image decoder.
-//
-// The TIFF specification is at http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf
-package tiff
-
-import (
-       "compress/lzw"
-       "compress/zlib"
-       "encoding/binary"
-       "image"
-       "image/color"
-       "io"
-       "io/ioutil"
-)
-
-// A FormatError reports that the input is not a valid TIFF image.
-type FormatError string
-
-func (e FormatError) Error() string {
-       return "tiff: invalid format: " + string(e)
-}
-
-// An UnsupportedError reports that the input uses a valid but
-// unimplemented feature.
-type UnsupportedError string
-
-func (e UnsupportedError) Error() string {
-       return "tiff: unsupported feature: " + string(e)
-}
-
-// An InternalError reports that an internal error was encountered.
-type InternalError string
-
-func (e InternalError) Error() string {
-       return "tiff: internal error: " + string(e)
-}
-
-type decoder struct {
-       r         io.ReaderAt
-       byteOrder binary.ByteOrder
-       config    image.Config
-       mode      imageMode
-       features  map[int][]uint
-       palette   []color.Color
-
-       buf   []byte
-       off   int    // Current offset in buf.
-       v     uint32 // Buffer value for reading with arbitrary bit depths.
-       nbits uint   // Remaining number of bits in v.
-}
-
-// firstVal returns the first uint of the features entry with the given tag,
-// or 0 if the tag does not exist.
-func (d *decoder) firstVal(tag int) uint {
-       f := d.features[tag]
-       if len(f) == 0 {
-               return 0
-       }
-       return f[0]
-}
-
-// ifdUint decodes the IFD entry in p, which must be of the Byte, Short
-// or Long type, and returns the decoded uint values.
-func (d *decoder) ifdUint(p []byte) (u []uint, err error) {
-       var raw []byte
-       datatype := d.byteOrder.Uint16(p[2:4])
-       count := d.byteOrder.Uint32(p[4:8])
-       if datalen := lengths[datatype] * count; datalen > 4 {
-               // The IFD contains a pointer to the real value.
-               raw = make([]byte, datalen)
-               _, err = d.r.ReadAt(raw, int64(d.byteOrder.Uint32(p[8:12])))
-       } else {
-               raw = p[8 : 8+datalen]
-       }
-       if err != nil {
-               return nil, err
-       }
-
-       u = make([]uint, count)
-       switch datatype {
-       case dtByte:
-               for i := uint32(0); i < count; i++ {
-                       u[i] = uint(raw[i])
-               }
-       case dtShort:
-               for i := uint32(0); i < count; i++ {
-                       u[i] = uint(d.byteOrder.Uint16(raw[2*i : 2*(i+1)]))
-               }
-       case dtLong:
-               for i := uint32(0); i < count; i++ {
-                       u[i] = uint(d.byteOrder.Uint32(raw[4*i : 4*(i+1)]))
-               }
-       default:
-               return nil, UnsupportedError("data type")
-       }
-       return u, nil
-}
-
-// parseIFD decides whether the the IFD entry in p is "interesting" and
-// stows away the data in the decoder.
-func (d *decoder) parseIFD(p []byte) error {
-       tag := d.byteOrder.Uint16(p[0:2])
-       switch tag {
-       case tBitsPerSample,
-               tExtraSamples,
-               tPhotometricInterpretation,
-               tCompression,
-               tPredictor,
-               tStripOffsets,
-               tStripByteCounts,
-               tRowsPerStrip,
-               tImageLength,
-               tImageWidth:
-               val, err := d.ifdUint(p)
-               if err != nil {
-                       return err
-               }
-               d.features[int(tag)] = val
-       case tColorMap:
-               val, err := d.ifdUint(p)
-               if err != nil {
-                       return err
-               }
-               numcolors := len(val) / 3
-               if len(val)%3 != 0 || numcolors <= 0 || numcolors > 256 {
-                       return FormatError("bad ColorMap length")
-               }
-               d.palette = make([]color.Color, numcolors)
-               for i := 0; i < numcolors; i++ {
-                       d.palette[i] = color.RGBA64{
-                               uint16(val[i]),
-                               uint16(val[i+numcolors]),
-                               uint16(val[i+2*numcolors]),
-                               0xffff,
-                       }
-               }
-       case tSampleFormat:
-               // Page 27 of the spec: If the SampleFormat is present and
-               // the value is not 1 [= unsigned integer data], a Baseline
-               // TIFF reader that cannot handle the SampleFormat value
-               // must terminate the import process gracefully.
-               val, err := d.ifdUint(p)
-               if err != nil {
-                       return err
-               }
-               for _, v := range val {
-                       if v != 1 {
-                               return UnsupportedError("sample format")
-                       }
-               }
-       }
-       return nil
-}
-
-// readBits reads n bits from the internal buffer starting at the current offset.
-func (d *decoder) readBits(n uint) uint32 {
-       for d.nbits < n {
-               d.v <<= 8
-               d.v |= uint32(d.buf[d.off])
-               d.off++
-               d.nbits += 8
-       }
-       d.nbits -= n
-       rv := d.v >> d.nbits
-       d.v &^= rv << d.nbits
-       return rv
-}
-
-// flushBits discards the unread bits in the buffer used by readBits.
-// It is used at the end of a line.
-func (d *decoder) flushBits() {
-       d.v = 0
-       d.nbits = 0
-}
-
-// decode decodes the raw data of an image.
-// It reads from d.buf and writes the strip with ymin <= y < ymax into dst.
-func (d *decoder) decode(dst image.Image, ymin, ymax int) error {
-       d.off = 0
-
-       // Apply horizontal predictor if necessary.
-       // In this case, p contains the color difference to the preceding pixel.
-       // See page 64-65 of the spec.
-       if d.firstVal(tPredictor) == prHorizontal && d.firstVal(tBitsPerSample) == 8 {
-               var off int
-               spp := len(d.features[tBitsPerSample]) // samples per pixel
-               for y := ymin; y < ymax; y++ {
-                       off += spp
-                       for x := 0; x < (dst.Bounds().Dx()-1)*spp; x++ {
-                               d.buf[off] += d.buf[off-spp]
-                               off++
-                       }
-               }
-       }
-
-       switch d.mode {
-       case mGray, mGrayInvert:
-               img := dst.(*image.Gray)
-               bpp := d.firstVal(tBitsPerSample)
-               max := uint32((1 << bpp) - 1)
-               for y := ymin; y < ymax; y++ {
-                       for x := img.Rect.Min.X; x < img.Rect.Max.X; x++ {
-                               v := uint8(d.readBits(bpp) * 0xff / max)
-                               if d.mode == mGrayInvert {
-                                       v = 0xff - v
-                               }
-                               img.SetGray(x, y, color.Gray{v})
-                       }
-                       d.flushBits()
-               }
-       case mPaletted:
-               img := dst.(*image.Paletted)
-               bpp := d.firstVal(tBitsPerSample)
-               for y := ymin; y < ymax; y++ {
-                       for x := img.Rect.Min.X; x < img.Rect.Max.X; x++ {
-                               img.SetColorIndex(x, y, uint8(d.readBits(bpp)))
-                       }
-                       d.flushBits()
-               }
-       case mRGB:
-               img := dst.(*image.RGBA)
-               min := img.PixOffset(0, ymin)
-               max := img.PixOffset(0, ymax)
-               var off int
-               for i := min; i < max; i += 4 {
-                       img.Pix[i+0] = d.buf[off+0]
-                       img.Pix[i+1] = d.buf[off+1]
-                       img.Pix[i+2] = d.buf[off+2]
-                       img.Pix[i+3] = 0xff
-                       off += 3
-               }
-       case mNRGBA:
-               img := dst.(*image.NRGBA)
-               min := img.PixOffset(0, ymin)
-               max := img.PixOffset(0, ymax)
-               if len(d.buf) != max-min {
-                       return FormatError("short data strip")
-               }
-               copy(img.Pix[min:max], d.buf)
-       case mRGBA:
-               img := dst.(*image.RGBA)
-               min := img.PixOffset(0, ymin)
-               max := img.PixOffset(0, ymax)
-               if len(d.buf) != max-min {
-                       return FormatError("short data strip")
-               }
-               copy(img.Pix[min:max], d.buf)
-       }
-
-       return nil
-}
-
-func newDecoder(r io.Reader) (*decoder, error) {
-       d := &decoder{
-               r:        newReaderAt(r),
-               features: make(map[int][]uint),
-       }
-
-       p := make([]byte, 8)
-       if _, err := d.r.ReadAt(p, 0); err != nil {
-               return nil, err
-       }
-       switch string(p[0:4]) {
-       case leHeader:
-               d.byteOrder = binary.LittleEndian
-       case beHeader:
-               d.byteOrder = binary.BigEndian
-       default:
-               return nil, FormatError("malformed header")
-       }
-
-       ifdOffset := int64(d.byteOrder.Uint32(p[4:8]))
-
-       // The first two bytes contain the number of entries (12 bytes each).
-       if _, err := d.r.ReadAt(p[0:2], ifdOffset); err != nil {
-               return nil, err
-       }
-       numItems := int(d.byteOrder.Uint16(p[0:2]))
-
-       // All IFD entries are read in one chunk.
-       p = make([]byte, ifdLen*numItems)
-       if _, err := d.r.ReadAt(p, ifdOffset+2); err != nil {
-               return nil, err
-       }
-
-       for i := 0; i < len(p); i += ifdLen {
-               if err := d.parseIFD(p[i : i+ifdLen]); err != nil {
-                       return nil, err
-               }
-       }
-
-       d.config.Width = int(d.firstVal(tImageWidth))
-       d.config.Height = int(d.firstVal(tImageLength))
-
-       if _, ok := d.features[tBitsPerSample]; !ok {
-               return nil, FormatError("BitsPerSample tag missing")
-       }
-
-       // Determine the image mode.
-       switch d.firstVal(tPhotometricInterpretation) {
-       case pRGB:
-               for _, b := range d.features[tBitsPerSample] {
-                       if b != 8 {
-                               return nil, UnsupportedError("non-8-bit RGB image")
-                       }
-               }
-               d.config.ColorModel = color.RGBAModel
-               // RGB images normally have 3 samples per pixel.
-               // If there are more, ExtraSamples (p. 31-32 of the spec)
-               // gives their meaning (usually an alpha channel).
-               //
-               // This implementation does not support extra samples
-               // of an unspecified type.
-               switch len(d.features[tBitsPerSample]) {
-               case 3:
-                       d.mode = mRGB
-               case 4:
-                       switch d.firstVal(tExtraSamples) {
-                       case 1:
-                               d.mode = mRGBA
-                       case 2:
-                               d.mode = mNRGBA
-                               d.config.ColorModel = color.NRGBAModel
-                       default:
-                               return nil, FormatError("wrong number of samples for RGB")
-                       }
-               default:
-                       return nil, FormatError("wrong number of samples for RGB")
-               }
-       case pPaletted:
-               d.mode = mPaletted
-               d.config.ColorModel = color.Palette(d.palette)
-       case pWhiteIsZero:
-               d.mode = mGrayInvert
-               d.config.ColorModel = color.GrayModel
-       case pBlackIsZero:
-               d.mode = mGray
-               d.config.ColorModel = color.GrayModel
-       default:
-               return nil, UnsupportedError("color model")
-       }
-
-       return d, nil
-}
-
-// DecodeConfig returns the color model and dimensions of a TIFF image without
-// decoding the entire image.
-func DecodeConfig(r io.Reader) (image.Config, error) {
-       d, err := newDecoder(r)
-       if err != nil {
-               return image.Config{}, err
-       }
-       return d.config, nil
-}
-
-// Decode reads a TIFF image from r and returns it as an image.Image.
-// The type of Image returned depends on the contents of the TIFF.
-func Decode(r io.Reader) (img image.Image, err error) {
-       d, err := newDecoder(r)
-       if err != nil {
-               return
-       }
-
-       // Check if we have the right number of strips, offsets and counts.
-       rps := int(d.firstVal(tRowsPerStrip))
-       if rps == 0 {
-               // Assume only one strip.
-               rps = d.config.Height
-       }
-       numStrips := (d.config.Height + rps - 1) / rps
-       if rps == 0 || len(d.features[tStripOffsets]) < numStrips || len(d.features[tStripByteCounts]) < numStrips {
-               return nil, FormatError("inconsistent header")
-       }
-
-       switch d.mode {
-       case mGray, mGrayInvert:
-               img = image.NewGray(image.Rect(0, 0, d.config.Width, d.config.Height))
-       case mPaletted:
-               img = image.NewPaletted(image.Rect(0, 0, d.config.Width, d.config.Height), d.palette)
-       case mNRGBA:
-               img = image.NewNRGBA(image.Rect(0, 0, d.config.Width, d.config.Height))
-       case mRGB, mRGBA:
-               img = image.NewRGBA(image.Rect(0, 0, d.config.Width, d.config.Height))
-       }
-
-       for i := 0; i < numStrips; i++ {
-               ymin := i * rps
-               // The last strip may be shorter.
-               if i == numStrips-1 && d.config.Height%rps != 0 {
-                       rps = d.config.Height % rps
-               }
-               offset := int64(d.features[tStripOffsets][i])
-               n := int64(d.features[tStripByteCounts][i])
-               switch d.firstVal(tCompression) {
-               case cNone:
-                       // TODO(bsiegert): Avoid copy if r is a tiff.buffer.
-                       d.buf = make([]byte, n)
-                       _, err = d.r.ReadAt(d.buf, offset)
-               case cLZW:
-                       r := lzw.NewReader(io.NewSectionReader(d.r, offset, n), lzw.MSB, 8)
-                       d.buf, err = ioutil.ReadAll(r)
-                       r.Close()
-               case cDeflate, cDeflateOld:
-                       r, err := zlib.NewReader(io.NewSectionReader(d.r, offset, n))
-                       if err != nil {
-                               return nil, err
-                       }
-                       d.buf, err = ioutil.ReadAll(r)
-                       r.Close()
-               case cPackBits:
-                       d.buf, err = unpackBits(io.NewSectionReader(d.r, offset, n))
-               default:
-                       err = UnsupportedError("compression")
-               }
-               if err != nil {
-                       return
-               }
-               err = d.decode(img, ymin, ymin+rps)
-       }
-       return
-}
-
-func init() {
-       image.RegisterFormat("tiff", leHeader, Decode, DecodeConfig)
-       image.RegisterFormat("tiff", beHeader, Decode, DecodeConfig)
-}
diff --git a/libgo/go/image/tiff/reader_test.go b/libgo/go/image/tiff/reader_test.go
deleted file mode 100644 (file)
index ee5dafd..0000000
+++ /dev/null
@@ -1,119 +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 tiff
-
-import (
-       "image"
-       "io/ioutil"
-       "os"
-       "strings"
-       "testing"
-)
-
-// Read makes *buffer implements io.Reader, so that we can pass one to Decode.
-func (*buffer) Read([]byte) (int, error) {
-       panic("unimplemented")
-}
-
-// TestNoRPS tries to decode an image that has no RowsPerStrip tag.
-// The tag is mandatory according to the spec but some software omits
-// it in the case of a single strip.
-func TestNoRPS(t *testing.T) {
-       f, err := os.Open("testdata/no_rps.tiff")
-       if err != nil {
-               t.Fatal(err)
-       }
-       defer f.Close()
-       _, err = Decode(f)
-       if err != nil {
-               t.Fatal(err)
-       }
-}
-
-// TestUnpackBits tests the decoding of PackBits-encoded data.
-func TestUnpackBits(t *testing.T) {
-       var unpackBitsTests = []struct {
-               compressed   string
-               uncompressed string
-       }{{
-               // Example data from Wikipedia.
-               "\xfe\xaa\x02\x80\x00\x2a\xfd\xaa\x03\x80\x00\x2a\x22\xf7\xaa",
-               "\xaa\xaa\xaa\x80\x00\x2a\xaa\xaa\xaa\xaa\x80\x00\x2a\x22\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa",
-       }}
-       for _, u := range unpackBitsTests {
-               buf, err := unpackBits(strings.NewReader(u.compressed))
-               if err != nil {
-                       t.Fatal(err)
-               }
-               if string(buf) != u.uncompressed {
-                       t.Fatalf("unpackBits: want %x, got %x", u.uncompressed, buf)
-               }
-       }
-}
-
-// TestDecompress tests that decoding some TIFF images that use different
-// compression formats result in the same pixel data.
-func TestDecompress(t *testing.T) {
-       var decompressTests = []string{
-               "bw-uncompressed.tiff",
-               "bw-deflate.tiff",
-               "bw-packbits.tiff",
-       }
-       var img0 image.Image
-       for _, name := range decompressTests {
-               f, err := os.Open("testdata/" + name)
-               if err != nil {
-                       t.Fatal(err)
-               }
-               defer f.Close()
-               if img0 == nil {
-                       img0, err = Decode(f)
-                       if err != nil {
-                               t.Fatalf("decoding %s: %v", name, err)
-                       }
-                       continue
-               }
-
-               img1, err := Decode(f)
-               if err != nil {
-                       t.Fatalf("decoding %s: %v", name, err)
-               }
-               b := img1.Bounds()
-               // Compare images.
-               if !b.Eq(img0.Bounds()) {
-                       t.Fatalf("wrong image size: want %s, got %s", img0.Bounds(), b)
-               }
-               for y := b.Min.Y; y < b.Max.Y; y++ {
-                       for x := b.Min.X; x < b.Max.X; x++ {
-                               c0 := img0.At(x, y)
-                               c1 := img1.At(x, y)
-                               r0, g0, b0, a0 := c0.RGBA()
-                               r1, g1, b1, a1 := c1.RGBA()
-                               if r0 != r1 || g0 != g1 || b0 != b1 || a0 != a1 {
-                                       t.Fatalf("pixel at (%d, %d) has wrong color: want %v, got %v", x, y, c0, c1)
-                               }
-                       }
-               }
-       }
-}
-
-const filename = "testdata/video-001-uncompressed.tiff"
-
-// BenchmarkDecode benchmarks the decoding of an image.
-func BenchmarkDecode(b *testing.B) {
-       b.StopTimer()
-       contents, err := ioutil.ReadFile(filename)
-       if err != nil {
-               panic(err)
-       }
-       r := &buffer{buf: contents}
-       b.StartTimer()
-       for i := 0; i < b.N; i++ {
-               _, err := Decode(r)
-               if err != nil {
-                       b.Fatal("Decode:", err)
-               }
-       }
-}
diff --git a/libgo/go/image/tiff/testdata/bw-deflate.tiff b/libgo/go/image/tiff/testdata/bw-deflate.tiff
deleted file mode 100644 (file)
index 137a0c3..0000000
Binary files a/libgo/go/image/tiff/testdata/bw-deflate.tiff and /dev/null differ
diff --git a/libgo/go/image/tiff/testdata/bw-packbits.tiff b/libgo/go/image/tiff/testdata/bw-packbits.tiff
deleted file mode 100644 (file)
index d59fa4a..0000000
Binary files a/libgo/go/image/tiff/testdata/bw-packbits.tiff and /dev/null differ
diff --git a/libgo/go/image/tiff/testdata/bw-uncompressed.tiff b/libgo/go/image/tiff/testdata/bw-uncompressed.tiff
deleted file mode 100644 (file)
index 8390f11..0000000
Binary files a/libgo/go/image/tiff/testdata/bw-uncompressed.tiff and /dev/null differ
diff --git a/libgo/go/image/tiff/testdata/no_rps.tiff b/libgo/go/image/tiff/testdata/no_rps.tiff
deleted file mode 100644 (file)
index 3280cf8..0000000
Binary files a/libgo/go/image/tiff/testdata/no_rps.tiff and /dev/null differ
diff --git a/libgo/go/image/tiff/testdata/video-001-uncompressed.tiff b/libgo/go/image/tiff/testdata/video-001-uncompressed.tiff
deleted file mode 100644 (file)
index fad1471..0000000
Binary files a/libgo/go/image/tiff/testdata/video-001-uncompressed.tiff and /dev/null differ
index 098d2234b4fb5aa63099a895699478fcd98c061a..bbfa6c2b2aadf71a0053bcb3c670bc3a500f5528 100644 (file)
@@ -8,30 +8,27 @@
 // abstract the functionality, plus some other related primitives.
 package io
 
-// Error represents an unexpected I/O behavior.
-type Error struct {
-       ErrorString string
-}
-
-func (err *Error) Error() string { return err.ErrorString }
+import (
+       "errors"
+)
 
 // ErrShortWrite means that a write accepted fewer bytes than requested
 // but failed to return an explicit error.
-var ErrShortWrite error = &Error{"short write"}
+var ErrShortWrite = errors.New("short write")
 
 // ErrShortBuffer means that a read required a longer buffer than was provided.
-var ErrShortBuffer error = &Error{"short buffer"}
+var ErrShortBuffer = errors.New("short buffer")
 
 // EOF is the error returned by Read when no more input is available.
 // Functions should return EOF only to signal a graceful end of input.
 // If the EOF occurs unexpectedly in a structured data stream,
 // the appropriate error is either ErrUnexpectedEOF or some other error
 // giving more detail.
-var EOF error = &Error{"EOF"}
+var EOF = errors.New("EOF")
 
 // ErrUnexpectedEOF means that EOF was encountered in the
 // middle of reading a fixed-size block or data structure.
-var ErrUnexpectedEOF error = &Error{"unexpected EOF"}
+var ErrUnexpectedEOF = errors.New("unexpected EOF")
 
 // Reader is the interface that wraps the basic Read method.
 //
@@ -220,6 +217,7 @@ type stringWriter interface {
 }
 
 // WriteString writes the contents of the string s to w, which accepts an array of bytes.
+// If w already implements a WriteString method, it is invoked directly.
 func WriteString(w Writer, s string) (n int, err error) {
        if sw, ok := w.(stringWriter); ok {
                return sw.WriteString(s)
@@ -268,7 +266,7 @@ func ReadFull(r Reader, buf []byte) (n int, err error) {
 // (including EOF), so can CopyN.
 //
 // If dst implements the ReaderFrom interface,
-// the copy is implemented by calling dst.ReadFrom(src).
+// the copy is implemented using it.
 func CopyN(dst Writer, src Reader, n int64) (written int64, err error) {
        // If the writer has a ReadFrom method, use it to do the copy.
        // Avoids a buffer allocation and a copy.
@@ -411,8 +409,8 @@ func (s *SectionReader) Read(p []byte) (n int, err error) {
        return
 }
 
-var errWhence = &Error{"Seek: invalid whence"}
-var errOffset = &Error{"Seek: invalid offset"}
+var errWhence = errors.New("Seek: invalid whence")
+var errOffset = errors.New("Seek: invalid offset")
 
 func (s *SectionReader) Seek(offset int64, whence int) (ret int64, err error) {
        switch whence {
index cbe1a5839df3256c109099b9ece9621d84b2901d..180afc2c221459f39a4d20d89b55e3540d8efb79 100644 (file)
@@ -34,11 +34,17 @@ func readAll(r io.Reader, capacity int64) (b []byte, err error) {
 }
 
 // ReadAll reads from r until an error or EOF and returns the data it read.
+// A successful call returns err == nil, not err == EOF. Because ReadAll is
+// defined to read from src until EOF, it does not treat an EOF from Read
+// as an error to be reported.
 func ReadAll(r io.Reader) ([]byte, error) {
        return readAll(r, bytes.MinRead)
 }
 
 // ReadFile reads the file named by filename and returns the contents.
+// A successful call returns err == nil, not err == EOF. Because ReadFile
+// reads the whole file, it does not treat an EOF from Read as an error
+// to be reported.
 func ReadFile(filename string) ([]byte, error) {
        f, err := os.Open(filename)
        if err != nil {
index 3dcff0d62a16d3f0c4b0c8184b9f8cd3aa0aba01..cf05e0c1ad7e3b5fb1a906942c7583a768a12bd8 100644 (file)
@@ -7,10 +7,13 @@
 
 package io
 
-import "sync"
+import (
+       "errors"
+       "sync"
+)
 
 // ErrClosedPipe is the error used for read or write operations on a closed pipe.
-var ErrClosedPipe = &Error{"io: read/write on closed pipe"}
+var ErrClosedPipe = errors.New("io: read/write on closed pipe")
 
 type pipeResult struct {
        n   int
index 8d556377f59a4011668e6860248e2d4b35cb4eea..c6c8645e1ae81c631d3ceed0c6f2a6cd8fd8bef8 100644 (file)
@@ -44,11 +44,9 @@ func Acosh(x float64) float64 {
                Ln2   = 6.93147180559945286227e-01 // 0x3FE62E42FEFA39EF
                Large = 1 << 28                    // 2**28
        )
-       // TODO(rsc): Remove manual inlining of IsNaN
-       // when compiler does it for us
        // first case is special case
        switch {
-       case x < 1 || x != x: // x < 1 || IsNaN(x):
+       case x < 1 || IsNaN(x):
                return NaN()
        case x == 1:
                return 0
index f786dd9f8f0996dd4f7339310471f8bab68132d7..0defbb9bef26c7f4c2ffb39c76436e5b1346a169 100644 (file)
@@ -42,10 +42,8 @@ func Asinh(x float64) float64 {
                NearZero = 1.0 / (1 << 28)            // 2**-28
                Large    = 1 << 28                    // 2**28
        )
-       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
-       // when compiler does it for us
        // special cases
-       if x != x || x > MaxFloat64 || x < -MaxFloat64 { // IsNaN(x) || IsInf(x, 0)
+       if IsNaN(x) || IsInf(x, 0) {
                return x
        }
        sign := false
index 02b045b9dc20afffebb25b95b9b8f33c90e364b3..48ed9a986b89723779de81ba282070b1e414844e 100644 (file)
@@ -35,11 +35,9 @@ func Atan2(y, x float64) float64 {
 }
 
 func atan2(y, x float64) float64 {
-       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
-       // when compiler does it for us
        // special cases
        switch {
-       case y != y || x != x: // IsNaN(y) || IsNaN(x):
+       case IsNaN(y) || IsNaN(x):
                return NaN()
        case y == 0:
                if x >= 0 && !Signbit(x) {
@@ -48,22 +46,22 @@ func atan2(y, x float64) float64 {
                return Copysign(Pi, y)
        case x == 0:
                return Copysign(Pi/2, y)
-       case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0):
-               if x > MaxFloat64 { // IsInf(x, 1) {
+       case IsInf(x, 0):
+               if IsInf(x, 1) {
                        switch {
-                       case y < -MaxFloat64 || y > MaxFloat64: // IsInf(y, -1) || IsInf(y, 1):
+                       case IsInf(y, 0):
                                return Copysign(Pi/4, y)
                        default:
                                return Copysign(0, y)
                        }
                }
                switch {
-               case y < -MaxFloat64 || y > MaxFloat64: // IsInf(y, -1) || IsInf(y, 1):
+               case IsInf(y, 0):
                        return Copysign(3*Pi/4, y)
                default:
                        return Copysign(Pi, y)
                }
-       case y < -MaxFloat64 || y > MaxFloat64: //IsInf(y, 0):
+       case IsInf(y, 0):
                return Copysign(Pi/2, y)
        }
 
index e150673c7001d0945ccc97d11012575166fbc096..5b5d468559bd066e658628e0db86bcdec3d3d3b4 100644 (file)
@@ -46,11 +46,9 @@ package math
 //     Atanh(NaN) = NaN
 func Atanh(x float64) float64 {
        const NearZero = 1.0 / (1 << 28) // 2**-28
-       // TODO(rsc): Remove manual inlining of IsNaN
-       // when compiler does it for us
        // special cases
        switch {
-       case x < -1 || x > 1 || x != x: // x < -1 || x > 1 || IsNaN(x):
+       case x < -1 || x > 1 || IsNaN(x):
                return NaN()
        case x == 1:
                return Inf(1)
index 41de17ba416f50bae06bf0f30a70e538ef3e01d8..306bf0ac65bcad7e58d44031c60996913f4de1ab 100644 (file)
@@ -8,8 +8,7 @@
 
 package big
 
-// TODO(gri) Decide if Word needs to remain exported.
-
+// A Word represents a single digit of a multi-precision unsigned integer.
 type Word uintptr
 
 const (
index 35e2e2941832294032ef563298b87ad31b45454f..cd2cd0e2da0bcff313bec421e11b827ecbeb3365 100644 (file)
@@ -65,6 +65,26 @@ func (z *Int) Set(x *Int) *Int {
        return z
 }
 
+// Bits provides raw (unchecked but fast) access to x by returning its
+// absolute value as a little-endian Word slice. The result and x share
+// the same underlying array.
+// Bits is intended to support implementation of missing low-level Int
+// functionality outside this package; it should be avoided otherwise.
+func (x *Int) Bits() []Word {
+       return x.abs
+}
+
+// SetBits provides raw (unchecked but fast) access to z by setting its
+// value to abs, interpreted as a little-endian Word slice, and returning
+// z. The result and abs share the same underlying array.
+// SetBits is intended to support implementation of missing low-level Int
+// functionality outside this package; it should be avoided otherwise.
+func (z *Int) SetBits(abs []Word) *Int {
+       z.abs = nat(abs).norm()
+       z.neg = false
+       return z
+}
+
 // Abs sets z to |x| (the absolute value of x) and returns z.
 func (z *Int) Abs(x *Int) *Int {
        z.Set(x)
@@ -191,6 +211,7 @@ func (z *Int) Rem(x, y *Int) *Int {
 //     r = x - y*q
 //
 // (See Daan Leijen, ``Division and Modulus for Computer Scientists''.)
+// See DivMod for Euclidean division and modulus (unlike Go).
 //
 func (z *Int) QuoRem(x, y, r *Int) (*Int, *Int) {
        z.abs, r.abs = z.abs.div(r.abs, x.abs, y.abs)
@@ -248,6 +269,7 @@ func (z *Int) Mod(x, y *Int) *Int {
 // div and mod''. ACM Transactions on Programming Languages and
 // Systems (TOPLAS), 14(2):127-144, New York, NY, USA, 4/1992.
 // ACM press.)
+// See QuoRem for T-division and modulus (like Go).
 //
 func (z *Int) DivMod(x, y, m *Int) (*Int, *Int) {
        y0 := y // save y
@@ -528,18 +550,18 @@ func (z *Int) SetBytes(buf []byte) *Int {
 }
 
 // Bytes returns the absolute value of z as a big-endian byte slice.
-func (z *Int) Bytes() []byte {
-       buf := make([]byte, len(z.abs)*_S)
-       return buf[z.abs.bytes(buf):]
+func (x *Int) Bytes() []byte {
+       buf := make([]byte, len(x.abs)*_S)
+       return buf[x.abs.bytes(buf):]
 }
 
 // BitLen returns the length of the absolute value of z in bits.
 // The bit length of 0 is 0.
-func (z *Int) BitLen() int {
-       return z.abs.bitLen()
+func (x *Int) BitLen() int {
+       return x.abs.bitLen()
 }
 
-// Exp sets z = x**y mod m. If m is nil, z = x**y.
+// Exp sets z = x**y mod m and returns z. If m is nil, z = x**y.
 // See Knuth, volume 2, section 4.6.3.
 func (z *Int) Exp(x, y, m *Int) *Int {
        if y.neg || len(y.abs) == 0 {
@@ -559,20 +581,20 @@ func (z *Int) Exp(x, y, m *Int) *Int {
        return z
 }
 
-// GcdInt sets d to the greatest common divisor of a and b, which must be
-// positive numbers.
-// If x and y are not nil, GcdInt sets x and y such that d = a*x + b*y.
-// If either a or b is not positive, GcdInt sets d = x = y = 0.
-func GcdInt(d, x, y, a, b *Int) {
+// GCD sets z to the greatest common divisor of a and b, which must be
+// positive numbers, and returns z.
+// If x and y are not nil, GCD sets x and y such that z = a*x + b*y.
+// If either a or b is not positive, GCD sets z = x = y = 0.
+func (z *Int) GCD(x, y, a, b *Int) *Int {
        if a.neg || b.neg {
-               d.SetInt64(0)
+               z.SetInt64(0)
                if x != nil {
                        x.SetInt64(0)
                }
                if y != nil {
                        y.SetInt64(0)
                }
-               return
+               return z
        }
 
        A := new(Int).Set(a)
@@ -614,14 +636,15 @@ func GcdInt(d, x, y, a, b *Int) {
                *y = *lastY
        }
 
-       *d = *A
+       *z = *A
+       return z
 }
 
-// ProbablyPrime performs n Miller-Rabin tests to check whether z is prime.
-// If it returns true, z is prime with probability 1 - 1/4^n.
-// If it returns false, z is not prime.
-func ProbablyPrime(z *Int, n int) bool {
-       return !z.neg && z.abs.probablyPrime(n)
+// ProbablyPrime performs n Miller-Rabin tests to check whether x is prime.
+// If it returns true, x is prime with probability 1 - 1/4^n.
+// If it returns false, x is not prime.
+func (x *Int) ProbablyPrime(n int) bool {
+       return !x.neg && x.abs.probablyPrime(n)
 }
 
 // Rand sets z to a pseudo-random number in [0, n) and returns z.
@@ -639,7 +662,7 @@ func (z *Int) Rand(rnd *rand.Rand, n *Int) *Int {
 // p is a prime) and returns z.
 func (z *Int) ModInverse(g, p *Int) *Int {
        var d Int
-       GcdInt(&d, z, nil, g, p)
+       d.GCD(z, nil, g, p)
        // x and y are such that g*x + p*y = d. Since p is prime, d = 1. Taking
        // that modulo p results in g*x = 1, therefore x is the inverse element.
        if z.neg {
@@ -671,18 +694,18 @@ func (z *Int) Rsh(x *Int, n uint) *Int {
        return z
 }
 
-// Bit returns the value of the i'th bit of z. That is, it
-// returns (z>>i)&1. The bit index i must be >= 0.
-func (z *Int) Bit(i int) uint {
+// Bit returns the value of the i'th bit of x. That is, it
+// returns (x>>i)&1. The bit index i must be >= 0.
+func (x *Int) Bit(i int) uint {
        if i < 0 {
                panic("negative bit index")
        }
-       if z.neg {
-               t := nat(nil).sub(z.abs, natOne)
+       if x.neg {
+               t := nat(nil).sub(x.abs, natOne)
                return t.bit(uint(i)) ^ 1
        }
 
-       return z.abs.bit(uint(i))
+       return x.abs.bit(uint(i))
 }
 
 // SetBit sets z to x, with x's i'th bit set to b (0 or 1).
@@ -847,11 +870,11 @@ func (z *Int) Not(x *Int) *Int {
 const intGobVersion byte = 1
 
 // GobEncode implements the gob.GobEncoder interface.
-func (z *Int) GobEncode() ([]byte, error) {
-       buf := make([]byte, 1+len(z.abs)*_S) // extra byte for version and sign bit
-       i := z.abs.bytes(buf) - 1            // i >= 0
+func (x *Int) GobEncode() ([]byte, error) {
+       buf := make([]byte, 1+len(x.abs)*_S) // extra byte for version and sign bit
+       i := x.abs.bytes(buf) - 1            // i >= 0
        b := intGobVersion << 1              // make space for sign bit
-       if z.neg {
+       if x.neg {
                b |= 1
        }
        buf[i] = b
index 9c4b730187404fd25278ac3128d68fe19ae494d4..9700a9b5a7ce875e206893093d61d6075958fa32 100644 (file)
@@ -824,7 +824,7 @@ func checkGcd(aBytes, bBytes []byte) bool {
        y := new(Int)
        d := new(Int)
 
-       GcdInt(d, x, y, a, b)
+       d.GCD(x, y, a, b)
        x.Mul(x, a)
        y.Mul(y, b)
        x.Add(x, y)
@@ -852,7 +852,7 @@ func TestGcd(t *testing.T) {
                expectedY := NewInt(test.y)
                expectedD := NewInt(test.d)
 
-               GcdInt(d, x, y, a, b)
+               d.GCD(x, y, a, b)
 
                if expectedX.Cmp(x) != 0 ||
                        expectedY.Cmp(y) != 0 ||
@@ -903,14 +903,14 @@ func TestProbablyPrime(t *testing.T) {
        }
        for i, s := range primes {
                p, _ := new(Int).SetString(s, 10)
-               if !ProbablyPrime(p, nreps) {
+               if !p.ProbablyPrime(nreps) {
                        t.Errorf("#%d prime found to be non-prime (%s)", i, s)
                }
        }
 
        for i, s := range composites {
                c, _ := new(Int).SetString(s, 10)
-               if ProbablyPrime(c, nreps) {
+               if c.ProbablyPrime(nreps) {
                        t.Errorf("#%d composite found to be prime (%s)", i, s)
                }
                if testing.Short() {
index 16f6ce9ba1bc6c1dd1ee053ce02a8c556861e728..6e1c7ffde4efded972547353485dd01005bea77c 100644 (file)
@@ -8,9 +8,15 @@
 //     - Int   signed integers
 //     - Rat   rational numbers
 //
-// All methods on Int take the result as the receiver; if it is one
-// of the operands it may be overwritten (and its memory reused).
-// To enable chaining of operations, the result is also returned.
+// Methods are typically of the form:
+//
+//     func (z *Int) Op(x, y *Int) *Int        (similar for *Rat)
+//
+// and implement operations z = x Op y with the result as receiver; if it
+// is one of the operands it may be overwritten (and its memory reused).
+// To enable chaining of operations, the result is also returned. Methods
+// returning a result other than *Int or *Rat take one of the operands as
+// the receiver.
 //
 package big
 
index adf412485f69e923575fc83d534dd10be9984828..7bd83fc0fb2820b688f0e23c5c648ad104d6d748 100644 (file)
@@ -328,36 +328,36 @@ func (z *Rat) SetString(s string) (*Rat, bool) {
 }
 
 // String returns a string representation of z in the form "a/b" (even if b == 1).
-func (z *Rat) String() string {
+func (x *Rat) String() string {
        s := "/1"
-       if len(z.b) != 0 {
-               s = "/" + z.b.decimalString()
+       if len(x.b) != 0 {
+               s = "/" + x.b.decimalString()
        }
-       return z.a.String() + s
+       return x.a.String() + s
 }
 
 // RatString returns a string representation of z in the form "a/b" if b != 1,
 // and in the form "a" if b == 1.
-func (z *Rat) RatString() string {
-       if z.IsInt() {
-               return z.a.String()
+func (x *Rat) RatString() string {
+       if x.IsInt() {
+               return x.a.String()
        }
-       return z.String()
+       return x.String()
 }
 
 // FloatString returns a string representation of z in decimal form with prec
 // digits of precision after the decimal point and the last digit rounded.
-func (z *Rat) FloatString(prec int) string {
-       if z.IsInt() {
-               s := z.a.String()
+func (x *Rat) FloatString(prec int) string {
+       if x.IsInt() {
+               s := x.a.String()
                if prec > 0 {
                        s += "." + strings.Repeat("0", prec)
                }
                return s
        }
-       // z.b != 0
+       // x.b != 0
 
-       q, r := nat(nil).div(nat(nil), z.a.abs, z.b)
+       q, r := nat(nil).div(nat(nil), x.a.abs, x.b)
 
        p := natOne
        if prec > 0 {
@@ -365,11 +365,11 @@ func (z *Rat) FloatString(prec int) string {
        }
 
        r = r.mul(r, p)
-       r, r2 := r.div(nat(nil), r, z.b)
+       r, r2 := r.div(nat(nil), r, x.b)
 
        // see if we need to round up
        r2 = r2.add(r2, r2)
-       if z.b.cmp(r2) <= 0 {
+       if x.b.cmp(r2) <= 0 {
                r = r.add(r, natOne)
                if r.cmp(p) >= 0 {
                        q = nat(nil).add(q, natOne)
@@ -378,7 +378,7 @@ func (z *Rat) FloatString(prec int) string {
        }
 
        s := q.decimalString()
-       if z.a.neg {
+       if x.a.neg {
                s = "-" + s
        }
 
@@ -395,10 +395,10 @@ func (z *Rat) FloatString(prec int) string {
 const ratGobVersion byte = 1
 
 // GobEncode implements the gob.GobEncoder interface.
-func (z *Rat) GobEncode() ([]byte, error) {
-       buf := make([]byte, 1+4+(len(z.a.abs)+len(z.b))*_S) // extra bytes for version and sign bit (1), and numerator length (4)
-       i := z.b.bytes(buf)
-       j := z.a.abs.bytes(buf[0:i])
+func (x *Rat) GobEncode() ([]byte, error) {
+       buf := make([]byte, 1+4+(len(x.a.abs)+len(x.b))*_S) // extra bytes for version and sign bit (1), and numerator length (4)
+       i := x.b.bytes(buf)
+       j := x.a.abs.bytes(buf[0:i])
        n := i - j
        if int(uint32(n)) != n {
                // this should never happen
@@ -407,7 +407,7 @@ func (z *Rat) GobEncode() ([]byte, error) {
        binary.BigEndian.PutUint32(buf[j-4:j], uint32(n))
        j -= 1 + 4
        b := ratGobVersion << 1 // make space for sign bit
-       if z.a.neg {
+       if x.a.neg {
                b |= 1
        }
        buf[j] = b
index 09edc0eae881ab6f8c6b827898bb03ccde796c3a..8c43f0afbc8858f997d481741cca63fb345573a8 100644 (file)
@@ -33,11 +33,9 @@ func Cbrt(x float64) float64 {
                C3 = 6.46502159e-02
                C4 = 1.412333954e-01
        )
-       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
-       // when compiler does it for us
        // special cases
        switch {
-       case x == 0 || x != x || x < -MaxFloat64 || x > MaxFloat64: // x == 0 || IsNaN(x) || IsInf(x, 0):
+       case x == 0 || IsNaN(x) || IsInf(x, 0):
                return x
        }
        sign := false
index 24a84e6d03b54c64b72ee045756a2616cefe679b..37ab5388073b97cc71b4d7d602fdc595d98a40fd 100644 (file)
@@ -30,13 +30,11 @@ func Max(x, y float64) float64 {
 }
 
 func max(x, y float64) float64 {
-       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
-       // when compiler does it for us
        // special cases
        switch {
-       case x > MaxFloat64 || y > MaxFloat64: // IsInf(x, 1) || IsInf(y, 1):
+       case IsInf(x, 1) || IsInf(y, 1):
                return Inf(1)
-       case x != x || y != y: // IsNaN(x) || IsNaN(y):
+       case IsNaN(x) || IsNaN(y):
                return NaN()
        case x == 0 && x == y:
                if Signbit(x) {
@@ -61,13 +59,11 @@ func Min(x, y float64) float64 {
 }
 
 func min(x, y float64) float64 {
-       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
-       // when compiler does it for us
        // special cases
        switch {
-       case x < -MaxFloat64 || y < -MaxFloat64: // IsInf(x, -1) || IsInf(y, -1):
+       case IsInf(x, -1) || IsInf(y, -1):
                return Inf(-1)
-       case x != x || y != y: // IsNaN(x) || IsNaN(y):
+       case IsNaN(x) || IsNaN(y):
                return NaN()
        case x == 0 && x == y:
                if Signbit(x) {
index 6d3d9b7c53730f2634e33d923a27ec87ec692b6f..87c70c2512f616a869d911d4996b35650eb0369e 100644 (file)
@@ -191,14 +191,12 @@ func Erf(x float64) float64 {
                Small    = 1.0 / (1 << 28)        // 2**-28
        )
        // special cases
-       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
-       // when compiler does it for us
        switch {
-       case x != x: // IsNaN(x):
+       case IsNaN(x):
                return NaN()
-       case x > MaxFloat64: // IsInf(x, 1):
+       case IsInf(x, 1):
                return 1
-       case x < -MaxFloat64: // IsInf(x, -1):
+       case IsInf(x, -1):
                return -1
        }
        sign := false
@@ -267,14 +265,12 @@ func Erf(x float64) float64 {
 func Erfc(x float64) float64 {
        const Tiny = 1.0 / (1 << 56) // 2**-56
        // special cases
-       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
-       // when compiler does it for us
        switch {
-       case x != x: // IsNaN(x):
+       case IsNaN(x):
                return NaN()
-       case x > MaxFloat64: // IsInf(x, 1):
+       case IsInf(x, 1):
                return 0
-       case x < -MaxFloat64: // IsInf(x, -1):
+       case IsInf(x, -1):
                return 2
        }
        sign := false
index b2da631c6972cd24283a769c2fea5f3e5a38ba51..51330c21dc8cdc05749bbff3bbc259ea1578c76d 100644 (file)
@@ -106,13 +106,11 @@ func exp(x float64) float64 {
                NearZero  = 1.0 / (1 << 28) // 2**-28
        )
 
-       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
-       // when compiler does it for us
        // special cases
        switch {
-       case x != x || x > MaxFloat64: // IsNaN(x) || IsInf(x, 1):
+       case IsNaN(x) || IsInf(x, 1):
                return x
-       case x < -MaxFloat64: // IsInf(x, -1):
+       case IsInf(x, -1):
                return 0
        case x > Overflow:
                return Inf(1)
@@ -153,13 +151,11 @@ func exp2(x float64) float64 {
                Underflow = -1.0740e+03
        )
 
-       // TODO: remove manual inlining of IsNaN and IsInf
-       // when compiler does it for us
        // special cases
        switch {
-       case x != x || x > MaxFloat64: // IsNaN(x) || IsInf(x, 1):
+       case IsNaN(x) || IsInf(x, 1):
                return x
-       case x < -MaxFloat64: // IsInf(x, -1):
+       case IsInf(x, -1):
                return 0
        case x > Overflow:
                return Inf(1)
index e7705b06a86f5282f4327767794ccf9036532d17..f7e15dbbc9d491427574d70421d798e7c96b241b 100644 (file)
@@ -148,12 +148,10 @@ func expm1(x float64) float64 {
        )
 
        // special cases
-       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
-       // when compiler does it for us
        switch {
-       case x > MaxFloat64 || x != x: // IsInf(x, 1) || IsNaN(x):
+       case IsInf(x, 1) || IsNaN(x):
                return x
-       case x < -MaxFloat64: // IsInf(x, -1):
+       case IsInf(x, -1):
                return -1
        }
 
index abe6264d27f2412f158ed6d137a2e0cb12531cd4..b35066e58cbb9031fc8a67d97502d7716889b6d1 100644 (file)
@@ -19,9 +19,7 @@ func Floor(x float64) float64 {
 }
 
 func floor(x float64) float64 {
-       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
-       // when compiler does it for us
-       if x == 0 || x != x || x > MaxFloat64 || x < -MaxFloat64 { // x == 0 || IsNaN(x) || IsInf(x, 0)
+       if x == 0 || IsNaN(x) || IsInf(x, 0) {
                return x
        }
        if x < 0 {
@@ -68,9 +66,7 @@ func Trunc(x float64) float64 {
 }
 
 func trunc(x float64) float64 {
-       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
-       // when compiler does it for us
-       if x == 0 || x != x || x > MaxFloat64 || x < -MaxFloat64 { // x == 0 || IsNaN(x) || IsInf(x, 0)
+       if x == 0 || IsNaN(x) || IsInf(x, 0) {
                return x
        }
        d, _ := Modf(x)
index 6b928e714c59e3a6dac1c0bf6b6bedbed6c72ae1..4ad0aee54a42f80f0e4dbf0e3359c87043ac47a9 100644 (file)
@@ -18,13 +18,11 @@ func Frexp(f float64) (frac float64, exp int) {
 }
 
 func frexp(f float64) (frac float64, exp int) {
-       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
-       // when compiler does it for us
        // special cases
        switch {
        case f == 0:
                return f, 0 // correctly return -0
-       case f < -MaxFloat64 || f > MaxFloat64 || f != f: // IsInf(f, 0) || IsNaN(f):
+       case IsInf(f, 0) || IsNaN(f):
                return f, 0
        }
        f, exp = normalize(f)
index 7365d8e77541b0446f209e56b13c96444e6697cb..2385a53b8a5cc7819525b85dda1378440918d325 100644 (file)
@@ -121,7 +121,7 @@ func Gamma(x float64) float64 {
        const Euler = 0.57721566490153286060651209008240243104215933593992 // A001620
        // special cases
        switch {
-       case x < -MaxFloat64 || x != x: // IsInf(x, -1) || IsNaN(x):
+       case IsInf(x, -1) || IsNaN(x):
                return x
        case x < -170.5674972726612 || x > 171.61447887182298:
                return Inf(1)
index 5c7c3a832b3ced84ae75769047ce49846859fc18..57d8e3437207a6f033aabf08252b1a6839c420bf 100644 (file)
@@ -19,13 +19,11 @@ func Hypot(p, q float64) float64 {
 }
 
 func hypot(p, q float64) float64 {
-       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
-       // when compiler does it for us
        // special cases
        switch {
-       case p < -MaxFloat64 || p > MaxFloat64 || q < -MaxFloat64 || q > MaxFloat64: // IsInf(p, 0) || IsInf(q, 0):
+       case IsInf(p, 0) || IsInf(q, 0):
                return Inf(1)
-       case p != p || q != q: // IsNaN(p) || IsNaN(q):
+       case IsNaN(p) || IsNaN(q):
                return NaN()
        }
        if p < 0 {
index 5aaf4ab9cf49c6204ae2c9721f55d1c4e23be90c..c20a9b22a89a761731b6adafe4a3839c1cfa5838 100644 (file)
@@ -89,13 +89,11 @@ func J0(x float64) float64 {
                S03 = 5.13546550207318111446e-07  // 0x3EA13B54CE84D5A9
                S04 = 1.16614003333790000205e-09  // 0x3E1408BCF4745D8F
        )
-       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
-       // when compiler does it for us
        // special cases
        switch {
-       case x != x: // IsNaN(x)
+       case IsNaN(x):
                return x
-       case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0):
+       case IsInf(x, 0):
                return 0
        case x == 0:
                return 1
@@ -171,13 +169,11 @@ func Y0(x float64) float64 {
                V03    = 2.59150851840457805467e-07  // 0x3E91642D7FF202FD
                V04    = 4.41110311332675467403e-10  // 0x3DFE50183BD6D9EF
        )
-       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
-       // when compiler does it for us
        // special cases
        switch {
-       case x < 0 || x != x: // x < 0 || IsNaN(x):
+       case x < 0 || IsNaN(x):
                return NaN()
-       case x > MaxFloat64: // IsInf(x, 1):
+       case IsInf(x, 1):
                return 0
        case x == 0:
                return Inf(-1)
index 278162e9d35855473263463468a0ffe67b679c7e..7ac186b72aa26cc0f92adf8c15e664708f54f099 100644 (file)
@@ -86,13 +86,11 @@ func J1(x float64) float64 {
                S04 = 5.04636257076217042715e-09  // 0x3E35AC88C97DFF2C
                S05 = 1.23542274426137913908e-11  // 0x3DAB2ACFCFB97ED8
        )
-       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
-       // when compiler does it for us
        // special cases
        switch {
-       case x != x: // IsNaN(x)
+       case IsNaN(x):
                return x
-       case x < -MaxFloat64 || x > MaxFloat64 || x == 0: // IsInf(x, 0) || x == 0:
+       case IsInf(x, 0) || x == 0:
                return 0
        }
 
@@ -168,13 +166,11 @@ func Y1(x float64) float64 {
                V03    = 6.22741452364621501295e-09  // 0x3E3ABF1D5BA69A86
                V04    = 1.66559246207992079114e-11  // 0x3DB25039DACA772A
        )
-       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
-       // when compiler does it for us
        // special cases
        switch {
-       case x < 0 || x != x: // x < 0 || IsNaN(x):
+       case x < 0 || IsNaN(x):
                return NaN()
-       case x > MaxFloat64: // IsInf(x, 1):
+       case IsInf(x, 1):
                return 0
        case x == 0:
                return Inf(-1)
index 1878df5b5a2682e39a21bd094eb59ae72177b901..a7909eb24cdd3f5e1fb23e4db7f996b230b8152d 100644 (file)
@@ -55,13 +55,11 @@ func Jn(n int, x float64) float64 {
                TwoM29 = 1.0 / (1 << 29) // 2**-29 0x3e10000000000000
                Two302 = 1 << 302        // 2**302 0x52D0000000000000
        )
-       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
-       // when compiler does it for us
        // special cases
        switch {
-       case x != x: // IsNaN(x)
+       case IsNaN(x):
                return x
-       case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0):
+       case IsInf(x, 0):
                return 0
        }
        // J(-n, x) = (-1)**n * J(n, x), J(n, -x) = (-1)**n * J(n, x)
@@ -236,13 +234,11 @@ func Jn(n int, x float64) float64 {
 //     Y1(n, NaN) = NaN
 func Yn(n int, x float64) float64 {
        const Two302 = 1 << 302 // 2**302 0x52D0000000000000
-       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
-       // when compiler does it for us
        // special cases
        switch {
-       case x < 0 || x != x: // x < 0 || IsNaN(x):
+       case x < 0 || IsNaN(x):
                return NaN()
-       case x > MaxFloat64: // IsInf(x, 1)
+       case IsInf(x, 1):
                return 0
        }
 
@@ -299,7 +295,7 @@ func Yn(n int, x float64) float64 {
                a := Y0(x)
                b = Y1(x)
                // quit if b is -inf
-               for i := 1; i < n && b >= -MaxFloat64; i++ { // for i := 1; i < n && !IsInf(b, -1); i++ {
+               for i := 1; i < n && !IsInf(b, -1); i++ {
                        a, b = b, (float64(i+i)/x)*b-a
                }
        }
index d5d78318d4858c461de99b55980cf2b5f74656b9..32c9853204d267947436d6d6bfe53758146f0651 100644 (file)
@@ -20,13 +20,11 @@ func Ldexp(frac float64, exp int) float64 {
 }
 
 func ldexp(frac float64, exp int) float64 {
-       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
-       // when compiler does it for us
        // special cases
        switch {
        case frac == 0:
                return frac // correctly return -0
-       case frac < -MaxFloat64 || frac > MaxFloat64 || frac != frac: // IsInf(frac, 0) || IsNaN(frac):
+       case IsInf(frac, 0) || IsNaN(frac):
                return frac
        }
        frac, e := normalize(frac)
index e2bad69dc03d0f8d9fa2245419122f3121f37846..6a02c412d93b603cc6d0abd3e0514ef9e2763a0b 100644 (file)
@@ -183,15 +183,13 @@ func Lgamma(x float64) (lgamma float64, sign int) {
                // Tt = -(tail of Tf)
                Tt = -3.63867699703950536541e-18 // 0xBC50C7CAA48A971F
        )
-       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
-       // when compiler does it for us
        // special cases
        sign = 1
        switch {
-       case x != x: // IsNaN(x):
+       case IsNaN(x):
                lgamma = x
                return
-       case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0):
+       case IsInf(x, 0):
                lgamma = x
                return
        case x == 0:
index 5e5c427c0faee3037e574f864e5a6dc4a135d178..60b57552d8bc747ab62723360854387c76531a36 100644 (file)
@@ -98,11 +98,9 @@ func log(x float64) float64 {
                L7    = 1.479819860511658591e-01   /* 3FC2F112 DF3E5244 */
        )
 
-       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
-       // when compiler does it for us
        // special cases
        switch {
-       case x != x || x > MaxFloat64: // IsNaN(x) || IsInf(x, 1):
+       case IsNaN(x) || IsInf(x, 1):
                return x
        case x < 0:
                return NaN()
index 15cd676ccc69174c30eb7ecc9be719d57797da81..c8daaaa1c95ab2293a690a93877cf31439943a82 100644 (file)
@@ -119,14 +119,12 @@ func log1p(x float64) float64 {
        )
 
        // special cases
-       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
-       // when compiler does it for us
        switch {
-       case x < -1 || x != x: // x < -1 || IsNaN(x): // includes -Inf
+       case x < -1 || IsNaN(x): // includes -Inf
                return NaN()
        case x == -1:
                return Inf(-1)
-       case x > MaxFloat64: // IsInf(x, 1):
+       case IsInf(x, 1):
                return Inf(1)
        }
 
index 072281ddf9f852de98fbe8793575e4cefd759524..d32f9f1000c790d042cb586c7e7e47c7af9b7c27 100644 (file)
@@ -11,15 +11,13 @@ package math
 //     Logb(0) = -Inf
 //     Logb(NaN) = NaN
 func Logb(x float64) float64 {
-       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
-       // when compiler does it for us
        // special cases
        switch {
        case x == 0:
                return Inf(-1)
-       case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0):
+       case IsInf(x, 0):
                return Inf(1)
-       case x != x: // IsNaN(x):
+       case IsNaN(x):
                return x
        }
        return float64(ilogb(x))
@@ -32,15 +30,13 @@ func Logb(x float64) float64 {
 //     Ilogb(0) = MinInt32
 //     Ilogb(NaN) = MaxInt32
 func Ilogb(x float64) int {
-       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
-       // when compiler does it for us
        // special cases
        switch {
        case x == 0:
                return MinInt32
-       case x != x: // IsNaN(x):
+       case IsNaN(x):
                return MaxInt32
-       case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0):
+       case IsInf(x, 0):
                return MaxInt32
        }
        return ilogb(x)
index dbb3aa00eb4b424ad421a89aa5ed2ad680f571a1..0b208f4eda3b43e12fa94efb4b8c83f86334746d 100644 (file)
@@ -27,9 +27,7 @@ func Mod(x, y float64) float64 {
 }
 
 func mod(x, y float64) float64 {
-       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
-       // when compiler does it for us.
-       if y == 0 || x > MaxFloat64 || x < -MaxFloat64 || x != x || y != y { // y == 0 || IsInf(x, 0) || IsNaN(x) || IsNan(y)
+       if y == 0 || IsInf(x, 0) || IsNaN(x) || IsNaN(y) {
                return NaN()
        }
        if y < 0 {
index e7723baacfb7e108e00df99de6b5726402a6c820..7c4b5bcdfef7eb2a5a58e0a73d285aada804f01c 100644 (file)
@@ -11,10 +11,8 @@ package math
 //      Nextafter(NaN, y) = NaN
 //      Nextafter(x, NaN) = NaN
 func Nextafter(x, y float64) (r float64) {
-       // TODO(rsc): Remove manual inlining of IsNaN
-       // when compiler does it for us
        switch {
-       case x != x || y != y: // IsNaN(x) || IsNaN(y): // special case
+       case IsNaN(x) || IsNaN(y): // special case
                r = NaN()
        case x == y:
                r = x
index f0f52c5cd4b034385da788bf7107cad23106a7f6..77af25648abf9d3c24c9828e6b6e8883dd484b1e 100644 (file)
@@ -36,8 +36,6 @@ func isOddInt(x float64) bool {
 //     Pow(-Inf, y) = Pow(-0, -y)
 //     Pow(x, y) = NaN for finite x < 0 and finite non-integer y
 func Pow(x, y float64) float64 {
-       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
-       // when compiler does it for us
        switch {
        case y == 0 || x == 1:
                return 1
@@ -47,7 +45,7 @@ func Pow(x, y float64) float64 {
                return Sqrt(x)
        case y == -0.5:
                return 1 / Sqrt(x)
-       case x != x || y != y: // IsNaN(x) || IsNaN(y):
+       case IsNaN(x) || IsNaN(y):
                return NaN()
        case x == 0:
                switch {
@@ -62,7 +60,7 @@ func Pow(x, y float64) float64 {
                        }
                        return 0
                }
-       case y > MaxFloat64 || y < -MaxFloat64: // IsInf(y, 0):
+       case IsInf(y, 0):
                switch {
                case x == -1:
                        return 1
@@ -71,7 +69,7 @@ func Pow(x, y float64) float64 {
                default:
                        return Inf(1)
                }
-       case x > MaxFloat64 || x < -MaxFloat64: // IsInf(x, 0):
+       case IsInf(x, 0):
                if IsInf(x, -1) {
                        return Pow(1/x, -y) // Pow(-0, -y)
                }
index 77811b183f52c7fd0a5b11c2b96b8a6d7f6222a4..a233e8ef188dfa86e1db7904d088e73d713d39cf 100644 (file)
@@ -43,13 +43,11 @@ func remainder(x, y float64) float64 {
                Tiny    = 4.45014771701440276618e-308 // 0x0020000000000000
                HalfMax = MaxFloat64 / 2
        )
-       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
-       // when compiler does it for us
        // special cases
        switch {
-       case x != x || y != y || x < -MaxFloat64 || x > MaxFloat64 || y == 0: // IsNaN(x) || IsNaN(y) || IsInf(x, 0) || y == 0:
+       case IsNaN(x) || IsNaN(y) || IsInf(x, 0) || y == 0:
                return NaN()
-       case y < -MaxFloat64 || y > MaxFloat64: // IsInf(y):
+       case IsInf(y, 0):
                return x
        }
        sign := false
index d692b3395d279b85625ce42226af27dfc9babfe1..13fe408ba06f06d19be7f7dbfdba6478f0511809 100644 (file)
@@ -129,11 +129,9 @@ func cos(x float64) float64 {
                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 != x || x < -MaxFloat64 || x > MaxFloat64: // IsNaN(x) || IsInf(x, 0):
+       case IsNaN(x) || IsInf(x, 0):
                return NaN()
        }
 
@@ -194,13 +192,11 @@ func sin(x float64) float64 {
                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 || x != x: // x == 0 || IsNaN():
+       case x == 0 || IsNaN(x):
                return x // return ±0 || NaN()
-       case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0):
+       case IsInf(x, 0):
                return NaN()
        }
 
index f0de0893e19ffad25f14e2e0943639e7d657c9bc..75e6e7541e63dc77427bf2f5aec37af1155459cb 100644 (file)
@@ -23,13 +23,11 @@ func sincos(x float64) (sin, cos float64) {
                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):
+       case IsNaN(x) || IsInf(x, 0):
                return NaN(), NaN()
        }
 
index 4f87f4183fe952789cb29f162cbffa983f52eac8..b5f297c84b6a3b7d9f35147740aef8d95f6793ce 100644 (file)
@@ -106,10 +106,8 @@ func Sqrt(x float64) float64 {
 //     Sqrt(NaN) = NaN
 func sqrt(x float64) float64 {
        // special cases
-       // TODO(rsc): Remove manual inlining of IsNaN, IsInf
-       // when compiler does it for us
        switch {
-       case x == 0 || x != x || x > MaxFloat64: // x == 0 || IsNaN(x) || IsInf(x, 1):
+       case x == 0 || IsNaN(x) || IsInf(x, 1):
                return x
        case x < 0:
                return NaN()
index 791ffc08e32d96e351e26ed364ccd9fa8613ec28..640f404fbe620fd68dc8574a403da571778874dd 100644 (file)
@@ -94,13 +94,11 @@ func tan(x float64) float64 {
                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 || x != x: // x == 0 || IsNaN():
+       case x == 0 || IsNaN(x):
                return x // return ±0 || NaN()
-       case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0):
+       case IsInf(x, 0):
                return NaN()
        }
 
index 64a11e6d9d908848eaf1c10c7f33d8b6ebb0deaf..d733130abb2e0dbe32857191e0563ffe0e6405a7 100644 (file)
@@ -112,13 +112,13 @@ func (bp *Part) populateHeaders() error {
 
 // Read reads the body of a part, after its headers and before the
 // next part (if any) begins.
-func (bp *Part) Read(p []byte) (n int, err error) {
-       if bp.buffer.Len() >= len(p) {
+func (p *Part) Read(d []byte) (n int, err error) {
+       if p.buffer.Len() >= len(d) {
                // Internal buffer of unconsumed data is large enough for
                // the read request.  No need to parse more at the moment.
-               return bp.buffer.Read(p)
+               return p.buffer.Read(d)
        }
-       peek, err := bp.mr.bufReader.Peek(4096) // TODO(bradfitz): add buffer size accessor
+       peek, err := p.mr.bufReader.Peek(4096) // TODO(bradfitz): add buffer size accessor
        unexpectedEof := err == io.EOF
        if err != nil && !unexpectedEof {
                return 0, fmt.Errorf("multipart: Part Read: %v", err)
@@ -133,10 +133,10 @@ func (bp *Part) Read(p []byte) (n int, err error) {
        // string.
        nCopy := 0
        foundBoundary := false
-       if idx := bytes.Index(peek, bp.mr.nlDashBoundary); idx != -1 {
+       if idx := bytes.Index(peek, p.mr.nlDashBoundary); idx != -1 {
                nCopy = idx
                foundBoundary = true
-       } else if safeCount := len(peek) - len(bp.mr.nlDashBoundary); safeCount > 0 {
+       } else if safeCount := len(peek) - len(p.mr.nlDashBoundary); safeCount > 0 {
                nCopy = safeCount
        } else if unexpectedEof {
                // If we've run out of peek buffer and the boundary
@@ -145,11 +145,11 @@ func (bp *Part) Read(p []byte) (n int, err error) {
                return 0, io.ErrUnexpectedEOF
        }
        if nCopy > 0 {
-               if _, err := io.CopyN(bp.buffer, bp.mr.bufReader, int64(nCopy)); err != nil {
+               if _, err := io.CopyN(p.buffer, p.mr.bufReader, int64(nCopy)); err != nil {
                        return 0, err
                }
        }
-       n, err = bp.buffer.Read(p)
+       n, err = p.buffer.Read(d)
        if err == io.EOF && !foundBoundary {
                // If the boundary hasn't been reached there's more to
                // read, so don't pass through an EOF from the buffer
@@ -158,8 +158,8 @@ func (bp *Part) Read(p []byte) (n int, err error) {
        return
 }
 
-func (bp *Part) Close() error {
-       io.Copy(ioutil.Discard, bp)
+func (p *Part) Close() error {
+       io.Copy(ioutil.Discard, p)
        return nil
 }
 
@@ -177,29 +177,29 @@ type Reader struct {
 
 // NextPart returns the next part in the multipart or an error.
 // When there are no more parts, the error io.EOF is returned.
-func (mr *Reader) NextPart() (*Part, error) {
-       if mr.currentPart != nil {
-               mr.currentPart.Close()
+func (r *Reader) NextPart() (*Part, error) {
+       if r.currentPart != nil {
+               r.currentPart.Close()
        }
 
        expectNewPart := false
        for {
-               line, err := mr.bufReader.ReadSlice('\n')
+               line, err := r.bufReader.ReadSlice('\n')
                if err != nil {
                        return nil, fmt.Errorf("multipart: NextPart: %v", err)
                }
 
-               if mr.isBoundaryDelimiterLine(line) {
-                       mr.partsRead++
-                       bp, err := newPart(mr)
+               if r.isBoundaryDelimiterLine(line) {
+                       r.partsRead++
+                       bp, err := newPart(r)
                        if err != nil {
                                return nil, err
                        }
-                       mr.currentPart = bp
+                       r.currentPart = bp
                        return bp, nil
                }
 
-               if hasPrefixThenNewline(line, mr.dashBoundaryDash) {
+               if hasPrefixThenNewline(line, r.dashBoundaryDash) {
                        // Expected EOF
                        return nil, io.EOF
                }
@@ -208,7 +208,7 @@ func (mr *Reader) NextPart() (*Part, error) {
                        return nil, fmt.Errorf("multipart: expecting a new Part; got line %q", string(line))
                }
 
-               if mr.partsRead == 0 {
+               if r.partsRead == 0 {
                        // skip line
                        continue
                }
@@ -217,7 +217,7 @@ func (mr *Reader) NextPart() (*Part, error) {
                // body of the previous part and the boundary line we
                // now expect will follow. (either a new part or the
                // end boundary)
-               if bytes.Equal(line, mr.nl) {
+               if bytes.Equal(line, r.nl) {
                        expectNewPart = true
                        continue
                }
index 16b726311534ed7409502f90e354060ebc327a58..de35ec9f940583ab6c54bd7e3331b9cc05d3c1a3 100644 (file)
@@ -43,18 +43,17 @@ func TestDialTimeout(t *testing.T) {
                                errc <- err
                        }()
                }
-       case "darwin":
+       case "darwin", "windows":
                // At least OS X 10.7 seems to accept any number of
                // connections, ignoring listen's backlog, so resort
                // to connecting to a hopefully-dead 127/8 address.
+               // Same for windows.
                go func() {
                        _, err := DialTimeout("tcp", "127.0.71.111:80", 200*time.Millisecond)
                        errc <- err
                }()
        default:
-               // TODO(bradfitz): this probably doesn't work on
-               // Windows? SOMAXCONN is huge there.  I'm not sure how
-               // listen works there.
+               // TODO(bradfitz):
                // OpenBSD may have a reject route to 10/8.
                // FreeBSD likely works, but is untested.
                t.Logf("skipping test on %q; untested.", runtime.GOOS)
index c0ab80288da349f8c9d5028849c210c076a9466b..bb46cc9007c621b2fa7121e23f5004fba8e7c948 100644 (file)
@@ -17,19 +17,6 @@ type dnsConfig struct {
        rotate   bool     // round robin among servers
 }
 
-var dnsconfigError error
-
-type DNSConfigError struct {
-       Err error
-}
-
-func (e *DNSConfigError) Error() string {
-       return "error reading DNS config: " + e.Err.Error()
-}
-
-func (e *DNSConfigError) Timeout() bool   { return false }
-func (e *DNSConfigError) Temporary() bool { return false }
-
 // See resolv.conf(5) on a Linux machine.
 // TODO(rsc): Supposed to call uname() and chop the beginning
 // of the host name to get the default search domain.
index 7595aa2ab593b73378a38e20f8a54865c57122ae..97c5062103fe0f72920e9fe1589ff9265d9dd26c 100644 (file)
@@ -4,7 +4,7 @@
 
 // DNS packet assembly.  See RFC 1035.
 //
-// This is intended to support name resolution during net.Dial.
+// This is intended to support name resolution during Dial.
 // It doesn't have to be blazing fast.
 //
 // Rather than write the usual handful of routines to pack and
index 495ef007fe20ea4a2b71efb2bd58f131155fe7ba..2352d22e115d6461acbb9a12dccee0ff882dc721 100644 (file)
@@ -43,12 +43,6 @@ type netFD struct {
        ncr, ncw int
 }
 
-type InvalidConnError struct{}
-
-func (e *InvalidConnError) Error() string   { return "invalid net.Conn" }
-func (e *InvalidConnError) Temporary() bool { return false }
-func (e *InvalidConnError) Timeout() bool   { return false }
-
 // A pollServer helps FDs determine when to retry a non-blocking
 // read or write after they get EAGAIN.  When an FD needs to wait,
 // send the fd on s.cr (for a read) or s.cw (for a write) to pass the
@@ -275,20 +269,20 @@ func startServer() {
        pollserver = p
 }
 
-func newFD(fd, family, sotype int, net string) (f *netFD, err error) {
+func newFD(fd, family, sotype int, net string) (*netFD, error) {
        onceStartServer.Do(startServer)
-       if e := syscall.SetNonblock(fd, true); e != nil {
-               return nil, e
+       if err := syscall.SetNonblock(fd, true); err != nil {
+               return nil, err
        }
-       = &netFD{
+       netfd := &netFD{
                sysfd:  fd,
                family: family,
                sotype: sotype,
                net:    net,
        }
-       f.cr = make(chan bool, 1)
-       f.cw = make(chan bool, 1)
-       return f, nil
+       netfd.cr = make(chan bool, 1)
+       netfd.cw = make(chan bool, 1)
+       return netfd, nil
 }
 
 func (fd *netFD) setAddr(laddr, raddr Addr) {
@@ -304,8 +298,8 @@ func (fd *netFD) setAddr(laddr, raddr Addr) {
        fd.sysfile = os.NewFile(fd.sysfd, fd.net+":"+ls+"->"+rs)
 }
 
-func (fd *netFD) connect(ra syscall.Sockaddr) (err error) {
-       err = syscall.Connect(fd.sysfd, ra)
+func (fd *netFD) connect(ra syscall.Sockaddr) error {
+       err := syscall.Connect(fd.sysfd, ra)
        if err == syscall.EINPROGRESS {
                pollserver.WaitWrite(fd)
                var e int
@@ -466,7 +460,7 @@ func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.S
        return
 }
 
-func (fd *netFD) Write(p []byte) (n int, err error) {
+func (fd *netFD) Write(p []byte) (int, error) {
        if fd == nil {
                return 0, os.EINVAL
        }
@@ -477,8 +471,9 @@ func (fd *netFD) Write(p []byte) (n int, err error) {
        if fd.sysfile == nil {
                return 0, os.EINVAL
        }
-       nn := 0
 
+       var err error
+       nn := 0
        for {
                var n int
                n, err = syscall.Write(fd.sysfile.Fd(), p[nn:])
@@ -565,7 +560,7 @@ func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oob
        return
 }
 
-func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err error) {
+func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (netfd *netFD, err error) {
        if fd == nil || fd.sysfile == nil {
                return nil, os.EINVAL
        }
@@ -600,13 +595,13 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err err
        syscall.CloseOnExec(s)
        syscall.ForkLock.RUnlock()
 
-       if nfd, err = newFD(s, fd.family, fd.sotype, fd.net); err != nil {
+       if netfd, err = newFD(s, fd.family, fd.sotype, fd.net); err != nil {
                syscall.Close(s)
                return nil, err
        }
-       lsa, _ := syscall.Getsockname(nfd.sysfd)
-       nfd.setAddr(toAddr(lsa), toAddr(rsa))
-       return nfd, nil
+       lsa, _ := syscall.Getsockname(netfd.sysfd)
+       netfd.setAddr(toAddr(lsa), toAddr(rsa))
+       return netfd, nil
 }
 
 func (fd *netFD) dup() (f *os.File, err error) {
index c8df9c9326a0b8dc418ec56739dd8f532d9f06dd..a1d62acc7840dc68127ed1dabb9c07f7028ea6ef 100644 (file)
@@ -35,17 +35,15 @@ type pollster struct {
 
 func newpollster() (p *pollster, err error) {
        p = new(pollster)
-       var e error
-
-       if p.epfd, e = syscall.EpollCreate1(syscall.EPOLL_CLOEXEC); e != nil {
-               if e != syscall.ENOSYS {
-                       return nil, os.NewSyscallError("epoll_create1", e)
+       if p.epfd, err = syscall.EpollCreate1(syscall.EPOLL_CLOEXEC); err != nil {
+               if err != syscall.ENOSYS {
+                       return nil, os.NewSyscallError("epoll_create1", err)
                }
                // The arg to epoll_create is a hint to the kernel
                // about the number of FDs we will care about.
                // We don't know, and since 2.6.8 the kernel ignores it anyhow.
-               if p.epfd, e = syscall.EpollCreate(16); e != nil {
-                       return nil, os.NewSyscallError("epoll_create", e)
+               if p.epfd, err = syscall.EpollCreate(16); err != nil {
+                       return nil, os.NewSyscallError("epoll_create", err)
                }
                syscall.CloseOnExec(p.epfd)
        }
@@ -74,8 +72,8 @@ func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, error) {
        } else {
                op = syscall.EPOLL_CTL_ADD
        }
-       if e := syscall.EpollCtl(p.epfd, op, fd, &p.ctlEvent); e != nil {
-               return false, os.NewSyscallError("epoll_ctl", e)
+       if err := syscall.EpollCtl(p.epfd, op, fd, &p.ctlEvent); err != nil {
+               return false, os.NewSyscallError("epoll_ctl", err)
        }
        p.events[fd] = p.ctlEvent.Events
        return false, nil
@@ -103,13 +101,13 @@ func (p *pollster) StopWaiting(fd int, bits uint) {
        if int32(events)&^syscall.EPOLLONESHOT != 0 {
                p.ctlEvent.Fd = int32(fd)
                p.ctlEvent.Events = events
-               if e := syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_MOD, fd, &p.ctlEvent); e != nil {
-                       print("Epoll modify fd=", fd, ": ", e.Error(), "\n")
+               if err := syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_MOD, fd, &p.ctlEvent); err != nil {
+                       print("Epoll modify fd=", fd, ": ", err.Error(), "\n")
                }
                p.events[fd] = events
        } else {
-               if e := syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_DEL, fd, nil); e != nil {
-                       print("Epoll delete fd=", fd, ": ", e.Error(), "\n")
+               if err := syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_DEL, fd, nil); err != nil {
+                       print("Epoll delete fd=", fd, ": ", err.Error(), "\n")
                }
                delete(p.events, fd)
        }
@@ -144,14 +142,14 @@ func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err erro
                }
 
                s.Unlock()
-               n, e := syscall.EpollWait(p.epfd, p.waitEventBuf[0:], msec)
+               n, err := syscall.EpollWait(p.epfd, p.waitEventBuf[0:], msec)
                s.Lock()
 
-               if e != nil {
-                       if e == syscall.EAGAIN || e == syscall.EINTR {
+               if err != nil {
+                       if err == syscall.EAGAIN || err == syscall.EINTR {
                                continue
                        }
-                       return -1, 0, os.NewSyscallError("epoll_wait", e)
+                       return -1, 0, os.NewSyscallError("epoll_wait", err)
                }
                if n == 0 {
                        return -1, 0, nil
index 31d0744e2cbe56af2447f2b14a84ce812bf607b1..35d84c30ef61122bffed2a81882a15d12a99f531 100644 (file)
@@ -49,12 +49,12 @@ func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, error) {
        }
        syscall.SetKevent(ev, fd, kmode, flags)
 
-       n, e := syscall.Kevent(p.kq, p.kbuf[:], nil, nil)
-       if e != nil {
-               return false, os.NewSyscallError("kevent", e)
+       n, err := syscall.Kevent(p.kq, p.kbuf[:], nil, nil)
+       if err != nil {
+               return false, os.NewSyscallError("kevent", err)
        }
        if n != 1 || (ev.Flags&syscall.EV_ERROR) == 0 || int(ev.Ident) != fd || int(ev.Filter) != kmode {
-               return false, os.NewSyscallError("kqueue phase error", e)
+               return false, os.NewSyscallError("kqueue phase error", err)
        }
        if ev.Data != 0 {
                return false, syscall.Errno(int(ev.Data))
@@ -88,19 +88,19 @@ func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err erro
                }
 
                s.Unlock()
-               nn, e := syscall.Kevent(p.kq, nil, p.eventbuf[:], t)
+               n, err := syscall.Kevent(p.kq, nil, p.eventbuf[:], t)
                s.Lock()
 
-               if e != nil {
-                       if e == syscall.EINTR {
+               if err != nil {
+                       if err == syscall.EINTR {
                                continue
                        }
-                       return -1, 0, os.NewSyscallError("kevent", e)
+                       return -1, 0, os.NewSyscallError("kevent", err)
                }
-               if nn == 0 {
+               if n == 0 {
                        return -1, 0, nil
                }
-               p.events = p.eventbuf[0:nn]
+               p.events = p.eventbuf[:n]
        }
        ev := &p.events[0]
        p.events = p.events[1:]
index 31d0744e2cbe56af2447f2b14a84ce812bf607b1..35d84c30ef61122bffed2a81882a15d12a99f531 100644 (file)
@@ -49,12 +49,12 @@ func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, error) {
        }
        syscall.SetKevent(ev, fd, kmode, flags)
 
-       n, e := syscall.Kevent(p.kq, p.kbuf[:], nil, nil)
-       if e != nil {
-               return false, os.NewSyscallError("kevent", e)
+       n, err := syscall.Kevent(p.kq, p.kbuf[:], nil, nil)
+       if err != nil {
+               return false, os.NewSyscallError("kevent", err)
        }
        if n != 1 || (ev.Flags&syscall.EV_ERROR) == 0 || int(ev.Ident) != fd || int(ev.Filter) != kmode {
-               return false, os.NewSyscallError("kqueue phase error", e)
+               return false, os.NewSyscallError("kqueue phase error", err)
        }
        if ev.Data != 0 {
                return false, syscall.Errno(int(ev.Data))
@@ -88,19 +88,19 @@ func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err erro
                }
 
                s.Unlock()
-               nn, e := syscall.Kevent(p.kq, nil, p.eventbuf[:], t)
+               n, err := syscall.Kevent(p.kq, nil, p.eventbuf[:], t)
                s.Lock()
 
-               if e != nil {
-                       if e == syscall.EINTR {
+               if err != nil {
+                       if err == syscall.EINTR {
                                continue
                        }
-                       return -1, 0, os.NewSyscallError("kevent", e)
+                       return -1, 0, os.NewSyscallError("kevent", err)
                }
-               if nn == 0 {
+               if n == 0 {
                        return -1, 0, nil
                }
-               p.events = p.eventbuf[0:nn]
+               p.events = p.eventbuf[:n]
        }
        ev := &p.events[0]
        p.events = p.events[1:]
index f00459f0bafe194f2c483429e2d789b6c34cabac..78168eb6c861436f43bdd8ee5c6e6753eaa66bc1 100644 (file)
@@ -14,12 +14,6 @@ import (
        "unsafe"
 )
 
-type InvalidConnError struct{}
-
-func (e *InvalidConnError) Error() string   { return "invalid net.Conn" }
-func (e *InvalidConnError) Temporary() bool { return false }
-func (e *InvalidConnError) Timeout() bool   { return false }
-
 var initErr error
 
 func init() {
@@ -30,7 +24,7 @@ func init() {
        }
 }
 
-func closesocket(s syscall.Handle) (err error) {
+func closesocket(s syscall.Handle) error {
        return syscall.Closesocket(s)
 }
 
@@ -38,7 +32,7 @@ func closesocket(s syscall.Handle) (err error) {
 type anOpIface interface {
        Op() *anOp
        Name() string
-       Submit() (err error)
+       Submit() error
 }
 
 // IO completion result parameters.
@@ -153,24 +147,25 @@ func (s *ioSrv) ProcessRemoteIO() {
 // inline, or, if a deadline is employed, passes the request onto
 // a special goroutine and waits for completion or cancels request.
 // deadline is unix nanos.
-func (s *ioSrv) ExecIO(oi anOpIface, deadline int64) (n int, err error) {
-       var e error
+func (s *ioSrv) ExecIO(oi anOpIface, deadline int64) (int, error) {
+       var err error
        o := oi.Op()
        if deadline != 0 {
                // Send request to a special dedicated thread,
                // so it can stop the io with CancelIO later.
                s.submchan <- oi
-               e = <-o.errnoc
+               err = <-o.errnoc
        } else {
-               e = oi.Submit()
+               err = oi.Submit()
        }
-       switch e {
+       switch err {
        case nil:
                // IO completed immediately, but we need to get our completion message anyway.
        case syscall.ERROR_IO_PENDING:
                // IO started, and we have to wait for its completion.
+               err = nil
        default:
-               return 0, &OpError{oi.Name(), o.fd.net, o.fd.laddr, e}
+               return 0, &OpError{oi.Name(), o.fd.net, o.fd.laddr, err}
        }
        // Wait for our request to complete.
        var r ioResult
@@ -245,25 +240,25 @@ type netFD struct {
        wio       sync.Mutex
 }
 
-func allocFD(fd syscall.Handle, family, sotype int, net string) (f *netFD) {
-       = &netFD{
+func allocFD(fd syscall.Handle, family, sotype int, net string) *netFD {
+       netfd := &netFD{
                sysfd:  fd,
                family: family,
                sotype: sotype,
                net:    net,
        }
-       runtime.SetFinalizer(f, (*netFD).Close)
-       return f
+       runtime.SetFinalizer(netfd, (*netFD).Close)
+       return netfd
 }
 
-func newFD(fd syscall.Handle, family, proto int, net string) (f *netFD, err error) {
+func newFD(fd syscall.Handle, family, proto int, net string) (*netFD, error) {
        if initErr != nil {
                return nil, initErr
        }
        onceStartServer.Do(startServer)
        // Associate our socket with resultsrv.iocp.
-       if _, e := syscall.CreateIoCompletionPort(syscall.Handle(fd), resultsrv.iocp, 0, 0); e != nil {
-               return nil, e
+       if _, err := syscall.CreateIoCompletionPort(syscall.Handle(fd), resultsrv.iocp, 0, 0); err != nil {
+               return nil, err
        }
        return allocFD(fd, family, proto, net), nil
 }
@@ -273,7 +268,7 @@ func (fd *netFD) setAddr(laddr, raddr Addr) {
        fd.raddr = raddr
 }
 
-func (fd *netFD) connect(ra syscall.Sockaddr) (err error) {
+func (fd *netFD) connect(ra syscall.Sockaddr) error {
        return syscall.Connect(fd.sysfd, ra)
 }
 
@@ -340,7 +335,7 @@ type readOp struct {
        bufOp
 }
 
-func (o *readOp) Submit() (err error) {
+func (o *readOp) Submit() error {
        var d, f uint32
        return syscall.WSARecv(syscall.Handle(o.fd.sysfd), &o.buf, 1, &d, &f, &o.o, nil)
 }
@@ -349,7 +344,7 @@ func (o *readOp) Name() string {
        return "WSARecv"
 }
 
-func (fd *netFD) Read(buf []byte) (n int, err error) {
+func (fd *netFD) Read(buf []byte) (int, error) {
        if fd == nil {
                return 0, os.EINVAL
        }
@@ -362,11 +357,11 @@ func (fd *netFD) Read(buf []byte) (n int, err error) {
        }
        var o readOp
        o.Init(fd, buf, 'r')
-       n, err = iosrv.ExecIO(&o, fd.rdeadline)
+       n, err := iosrv.ExecIO(&o, fd.rdeadline)
        if err == nil && n == 0 {
                err = io.EOF
        }
-       return
+       return n, err
 }
 
 // ReadFrom from network.
@@ -377,7 +372,7 @@ type readFromOp struct {
        rsan int32
 }
 
-func (o *readFromOp) Submit() (err error) {
+func (o *readFromOp) Submit() error {
        var d, f uint32
        return syscall.WSARecvFrom(o.fd.sysfd, &o.buf, 1, &d, &f, &o.rsa, &o.rsan, &o.o, nil)
 }
@@ -417,7 +412,7 @@ type writeOp struct {
        bufOp
 }
 
-func (o *writeOp) Submit() (err error) {
+func (o *writeOp) Submit() error {
        var d uint32
        return syscall.WSASend(o.fd.sysfd, &o.buf, 1, &d, 0, &o.o, nil)
 }
@@ -426,7 +421,7 @@ func (o *writeOp) Name() string {
        return "WSASend"
 }
 
-func (fd *netFD) Write(buf []byte) (n int, err error) {
+func (fd *netFD) Write(buf []byte) (int, error) {
        if fd == nil {
                return 0, os.EINVAL
        }
@@ -449,7 +444,7 @@ type writeToOp struct {
        sa syscall.Sockaddr
 }
 
-func (o *writeToOp) Submit() (err error) {
+func (o *writeToOp) Submit() error {
        var d uint32
        return syscall.WSASendto(o.fd.sysfd, &o.buf, 1, &d, 0, o.sa, &o.o, nil)
 }
@@ -458,7 +453,7 @@ func (o *writeToOp) Name() string {
        return "WSASendto"
 }
 
-func (fd *netFD) WriteTo(buf []byte, sa syscall.Sockaddr) (n int, err error) {
+func (fd *netFD) WriteTo(buf []byte, sa syscall.Sockaddr) (int, error) {
        if fd == nil {
                return 0, os.EINVAL
        }
@@ -486,7 +481,7 @@ type acceptOp struct {
        attrs   [2]syscall.RawSockaddrAny // space for local and remote address only
 }
 
-func (o *acceptOp) Submit() (err error) {
+func (o *acceptOp) Submit() error {
        var d uint32
        l := uint32(unsafe.Sizeof(o.attrs[0]))
        return syscall.AcceptEx(o.fd.sysfd, o.newsock,
@@ -497,7 +492,7 @@ func (o *acceptOp) Name() string {
        return "AcceptEx"
 }
 
-func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err error) {
+func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (*netFD, error) {
        if fd == nil || fd.sysfd == syscall.InvalidHandle {
                return nil, os.EINVAL
        }
@@ -507,18 +502,18 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err err
        // Get new socket.
        // See ../syscall/exec.go for description of ForkLock.
        syscall.ForkLock.RLock()
-       s, e := syscall.Socket(fd.family, fd.sotype, 0)
-       if e != nil {
+       s, err := syscall.Socket(fd.family, fd.sotype, 0)
+       if err != nil {
                syscall.ForkLock.RUnlock()
-               return nil, e
+               return nil, err
        }
        syscall.CloseOnExec(s)
        syscall.ForkLock.RUnlock()
 
        // Associate our new socket with IOCP.
        onceStartServer.Do(startServer)
-       if _, e = syscall.CreateIoCompletionPort(s, resultsrv.iocp, 0, 0); e != nil {
-               return nil, &OpError{"CreateIoCompletionPort", fd.net, fd.laddr, e}
+       if _, err := syscall.CreateIoCompletionPort(s, resultsrv.iocp, 0, 0); err != nil {
+               return nil, &OpError{"CreateIoCompletionPort", fd.net, fd.laddr, err}
        }
 
        // Submit accept request.
@@ -532,10 +527,10 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err err
        }
 
        // Inherit properties of the listening socket.
-       e = syscall.Setsockopt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd)))
-       if e != nil {
+       err = syscall.Setsockopt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd)))
+       if err != nil {
                closesocket(s)
-               return nil, e
+               return nil, err
        }
 
        // Get local and peer addr out of AcceptEx buffer.
@@ -547,14 +542,14 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err err
        lsa, _ := lrsa.Sockaddr()
        rsa, _ := rrsa.Sockaddr()
 
-       nfd = allocFD(s, fd.family, fd.sotype, fd.net)
-       nfd.setAddr(toAddr(lsa), toAddr(rsa))
-       return nfd, nil
+       netfd := allocFD(s, fd.family, fd.sotype, fd.net)
+       netfd.setAddr(toAddr(lsa), toAddr(rsa))
+       return netfd, nil
 }
 
 // Unimplemented functions.
 
-func (fd *netFD) dup() (f *os.File, err error) {
+func (fd *netFD) dup() (*os.File, error) {
        // TODO: Implement this
        return nil, os.NewSyscallError("dup", syscall.EWINDOWS)
 }
index 4ac280bd1a34b657ff35043e5471623b4a336bd1..901b8565995278353353107061763ba8f903749f 100644 (file)
@@ -11,15 +11,15 @@ import (
        "syscall"
 )
 
-func newFileFD(f *os.File) (nfd *netFD, err error) {
-       fd, errno := syscall.Dup(f.Fd())
-       if errno != nil {
-               return nil, os.NewSyscallError("dup", errno)
+func newFileFD(f *os.File) (*netFD, error) {
+       fd, err := syscall.Dup(f.Fd())
+       if err != nil {
+               return nil, os.NewSyscallError("dup", err)
        }
 
-       proto, errno := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_TYPE)
-       if errno != nil {
-               return nil, os.NewSyscallError("getsockopt", errno)
+       proto, err := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_TYPE)
+       if err != nil {
+               return nil, os.NewSyscallError("getsockopt", err)
        }
 
        family := syscall.AF_UNSPEC
@@ -56,11 +56,12 @@ func newFileFD(f *os.File) (nfd *netFD, err error) {
        sa, _ = syscall.Getpeername(fd)
        raddr := toAddr(sa)
 
-       if nfd, err = newFD(fd, family, proto, laddr.Network()); err != nil {
+       netfd, err := newFD(fd, family, proto, laddr.Network())
+       if err != nil {
                return nil, err
        }
-       nfd.setAddr(laddr, raddr)
-       return nfd, nil
+       netfd.setAddr(laddr, raddr)
+       return netfd, nil
 }
 
 // FileConn returns a copy of the network connection corresponding to
index 73a9b6ea6811c105a2cc2430fc5f89ef91db97d4..d27cc4dc9a8abfb6ba474cf85f26488d7903f6a2 100644 (file)
@@ -217,7 +217,7 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
        defer cmd.Wait()
        defer stdoutRead.Close()
 
-       linebody, _ := bufio.NewReaderSize(stdoutRead, 1024)
+       linebody := bufio.NewReaderSize(stdoutRead, 1024)
        headers := make(http.Header)
        statusCode := 0
        for {
index c9f024017573ea107bb42443a3b56f80badea05a..5d450258bd37798b035e15c891c02429375dbb29 100644 (file)
@@ -245,7 +245,11 @@ func (c *Client) doFollowingRedirects(ireq *Request) (r *Response, err error) {
        }
 
        method := ireq.Method
-       err = &url.Error{method[0:1] + strings.ToLower(method[1:]), urlStr, err}
+       err = &url.Error{
+               Op:  method[0:1] + strings.ToLower(method[1:]),
+               URL: urlStr,
+               Err: err,
+       }
        return
 }
 
@@ -274,7 +278,11 @@ func (c *Client) Post(url string, bodyType string, body io.Reader) (r *Response,
                return nil, err
        }
        req.Header.Set("Content-Type", bodyType)
-       return send(req, c.Transport)
+       r, err = send(req, c.Transport)
+       if err == nil && c.Jar != nil {
+               c.Jar.SetCookies(req.URL, r.Cookies())
+       }
+       return r, err
 }
 
 // PostForm issues a POST to the specified URL, 
index d35aa84d229aab920addb06265aa9768f43b1c1d..06bba0488a20f897936a2489dfef46ff8fbba72c 100644 (file)
@@ -240,7 +240,7 @@ func (w *bufWriter) Close() error {
 
 func newWriter(c *conn, recType recType, reqId uint16) *bufWriter {
        s := &streamWriter{c: c, recType: recType, reqId: reqId}
-       w, _ := bufio.NewWriterSize(s, maxWrite)
+       w := bufio.NewWriterSize(s, maxWrite)
        return &bufWriter{s, w}
 }
 
index 85cad3ec71b597cdbaef0ddb504d2e5e22326570..feea9209e6a362e1ec087a6111c38a4612575062 100644 (file)
@@ -190,7 +190,7 @@ func TestDirJoin(t *testing.T) {
                if err != nil {
                        t.Fatalf("stat of %s: %v", name, err)
                }
-               if !gfi.(*os.FileStat).SameFile(wfi.(*os.FileStat)) {
+               if !os.SameFile(gfi, wfi) {
                        t.Errorf("%s got different file", name)
                }
        }
index b8a98ee42929b033497f74acb19719304ddf9298..c853066f1cffa06f17a0f9f76091babe13e474d4 100644 (file)
@@ -5,8 +5,8 @@
 package httputil
 
 import (
+       "bufio"
        "bytes"
-       "errors"
        "fmt"
        "io"
        "io/ioutil"
@@ -47,40 +47,59 @@ func (c *dumpConn) SetWriteDeadline(t time.Time) error { return nil }
 // DumpRequestOut is like DumpRequest but includes
 // headers that the standard http.Transport adds,
 // such as User-Agent.
-func DumpRequestOut(req *http.Request, body bool) (dump []byte, err error) {
+func DumpRequestOut(req *http.Request, body bool) ([]byte, error) {
        save := req.Body
        if !body || req.Body == nil {
                req.Body = nil
        } else {
+               var err error
                save, req.Body, err = drainBody(req.Body)
                if err != nil {
-                       return
+                       return nil, err
                }
        }
 
-       var b bytes.Buffer
-       dialed := false
+       // Use the actual Transport code to record what we would send
+       // on the wire, but not using TCP.  Use a Transport with a
+       // customer dialer that returns a fake net.Conn that waits
+       // for the full input (and recording it), and then responds
+       // with a dummy response.
+       var buf bytes.Buffer // records the output
+       pr, pw := io.Pipe()
+       dr := &delegateReader{c: make(chan io.Reader)}
+       // Wait for the request before replying with a dummy response:
+       go func() {
+               http.ReadRequest(bufio.NewReader(pr))
+               dr.c <- strings.NewReader("HTTP/1.1 204 No Content\r\n\r\n")
+       }()
+
        t := &http.Transport{
-               Dial: func(net, addr string) (c net.Conn, err error) {
-                       if dialed {
-                               return nil, errors.New("unexpected second dial")
-                       }
-                       c = &dumpConn{
-                               Writer: &b,
-                               Reader: strings.NewReader("HTTP/1.1 500 Fake Error\r\n\r\n"),
-                       }
-                       return
+               Dial: func(net, addr string) (net.Conn, error) {
+                       return &dumpConn{io.MultiWriter(pw, &buf), dr}, nil
                },
        }
 
-       _, err = t.RoundTrip(req)
+       _, err := t.RoundTrip(req)
 
        req.Body = save
        if err != nil {
-               return
+               return nil, err
        }
-       dump = b.Bytes()
-       return
+       return buf.Bytes(), nil
+}
+
+// delegateReader is a reader that delegates to another reader,
+// once it arrives on a channel.
+type delegateReader struct {
+       c chan io.Reader
+       r io.Reader // nil until received from c
+}
+
+func (r *delegateReader) Read(p []byte) (int, error) {
+       if r.r == nil {
+               r.r = <-r.c
+       }
+       return r.r.Read(p)
 }
 
 // Return value if nonempty, def otherwise.
index 1266bd3ad22eb98414956543c5211b8cfacd234c..c065ccfb499a4d4d8f78836cf18431de437080be 100644 (file)
@@ -18,8 +18,8 @@ import (
 )
 
 var (
-       ErrPersistEOF = &http.ProtocolError{"persistent connection closed"}
-       ErrPipeline   = &http.ProtocolError{"pipeline error"}
+       ErrPersistEOF = &http.ProtocolError{ErrorString: "persistent connection closed"}
+       ErrPipeline   = &http.ProtocolError{ErrorString: "pipeline error"}
 )
 
 // This is an API usage error - the local side is closed.
index 1072e2e342604bb47fa32812f45569f73821cab1..9c4bd6e09a5c81aa09c9ea264b597b19ab21a2d0 100644 (file)
@@ -55,11 +55,16 @@ func singleJoiningSlash(a, b string) string {
 // target's path is "/base" and the incoming request was for "/dir",
 // the target request will be for /base/dir.
 func NewSingleHostReverseProxy(target *url.URL) *ReverseProxy {
+       targetQuery := target.RawQuery
        director := func(req *http.Request) {
                req.URL.Scheme = target.Scheme
                req.URL.Host = target.Host
                req.URL.Path = singleJoiningSlash(target.Path, req.URL.Path)
-               req.URL.RawQuery = target.RawQuery
+               if targetQuery == "" || req.URL.RawQuery == "" {
+                       req.URL.RawQuery = targetQuery + req.URL.RawQuery
+               } else {
+                       req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery
+               }
        }
        return &ReverseProxy{Director: director}
 }
index 655784b30d5f195d7603ffde0b0dac3247df2027..28e9c90ad36cdac93a4550a4384b1a481edbf1b6 100644 (file)
@@ -69,3 +69,41 @@ func TestReverseProxy(t *testing.T) {
                t.Errorf("got body %q; expected %q", g, e)
        }
 }
+
+var proxyQueryTests = []struct {
+       baseSuffix string // suffix to add to backend URL
+       reqSuffix  string // suffix to add to frontend's request URL
+       want       string // what backend should see for final request URL (without ?)
+}{
+       {"", "", ""},
+       {"?sta=tic", "?us=er", "sta=tic&us=er"},
+       {"", "?us=er", "us=er"},
+       {"?sta=tic", "", "sta=tic"},
+}
+
+func TestReverseProxyQuery(t *testing.T) {
+       backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+               w.Header().Set("X-Got-Query", r.URL.RawQuery)
+               w.Write([]byte("hi"))
+       }))
+       defer backend.Close()
+
+       for i, tt := range proxyQueryTests {
+               backendURL, err := url.Parse(backend.URL + tt.baseSuffix)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               frontend := httptest.NewServer(NewSingleHostReverseProxy(backendURL))
+               req, _ := http.NewRequest("GET", frontend.URL+tt.reqSuffix, nil)
+               req.Close = true
+               res, err := http.DefaultClient.Do(req)
+               if err != nil {
+                       t.Fatalf("%d. Get: %v", i, err)
+               }
+               if g, e := res.Header.Get("X-Got-Query"), tt.want; g != e {
+                       t.Errorf("%d. got query %q; expected %q", i, g, e)
+               }
+               res.Body.Close()
+               frontend.Close()
+       }
+}
index 5f8c00086bee74b09b5da98c1b4c1df3f6deab91..0bbec53be71d50d3bc233d3e1785cd47a3068566 100644 (file)
@@ -272,7 +272,7 @@ func valueOrDefault(value, def string) string {
 const defaultUserAgent = "Go http package"
 
 // Write writes an HTTP/1.1 request -- header and body -- in wire format.
-// This method consults the following fields of req:
+// This method consults the following fields of the request:
 //     Host
 //     URL
 //     Method (defaults to "GET")
@@ -284,18 +284,18 @@ const defaultUserAgent = "Go http package"
 // If Body is present, Content-Length is <= 0 and TransferEncoding
 // hasn't been set to "identity", Write adds "Transfer-Encoding:
 // chunked" to the header. Body is closed after it is sent.
-func (req *Request) Write(w io.Writer) error {
-       return req.write(w, false, nil)
+func (r *Request) Write(w io.Writer) error {
+       return r.write(w, false, nil)
 }
 
 // WriteProxy is like Write but writes the request in the form
 // expected by an HTTP proxy.  In particular, WriteProxy writes the
 // initial Request-URI line of the request with an absolute URI, per
-// section 5.1.2 of RFC 2616, including the scheme and host. In
-// either case, WriteProxy also writes a Host header, using either
-// req.Host or req.URL.Host.
-func (req *Request) WriteProxy(w io.Writer) error {
-       return req.write(w, true, nil)
+// section 5.1.2 of RFC 2616, including the scheme and host.
+// In either case, WriteProxy also writes a Host header, using
+// either r.Host or r.URL.Host.
+func (r *Request) WriteProxy(w io.Writer) error {
+       return r.write(w, true, nil)
 }
 
 // extraHeaders may be nil
index ae314b5ac934bfa942884a4ce96489458716684f..b79022097867992c5b6c011dec4ae9b9ea6df76d 100644 (file)
@@ -174,7 +174,7 @@ func (r *Response) ProtoAtLeast(major, minor int) bool {
 }
 
 // Writes the response (header, body and trailer) in wire format. This method
-// consults the following fields of resp:
+// consults the following fields of the response:
 //
 //  StatusCode
 //  ProtoMajor
@@ -186,28 +186,28 @@ func (r *Response) ProtoAtLeast(major, minor int) bool {
 //  ContentLength
 //  Header, values for non-canonical keys will have unpredictable behavior
 //
-func (resp *Response) Write(w io.Writer) error {
+func (r *Response) Write(w io.Writer) error {
 
        // RequestMethod should be upper-case
-       if resp.Request != nil {
-               resp.Request.Method = strings.ToUpper(resp.Request.Method)
+       if r.Request != nil {
+               r.Request.Method = strings.ToUpper(r.Request.Method)
        }
 
        // Status line
-       text := resp.Status
+       text := r.Status
        if text == "" {
                var ok bool
-               text, ok = statusText[resp.StatusCode]
+               text, ok = statusText[r.StatusCode]
                if !ok {
-                       text = "status code " + strconv.Itoa(resp.StatusCode)
+                       text = "status code " + strconv.Itoa(r.StatusCode)
                }
        }
-       io.WriteString(w, "HTTP/"+strconv.Itoa(resp.ProtoMajor)+".")
-       io.WriteString(w, strconv.Itoa(resp.ProtoMinor)+" ")
-       io.WriteString(w, strconv.Itoa(resp.StatusCode)+" "+text+"\r\n")
+       io.WriteString(w, "HTTP/"+strconv.Itoa(r.ProtoMajor)+".")
+       io.WriteString(w, strconv.Itoa(r.ProtoMinor)+" ")
+       io.WriteString(w, strconv.Itoa(r.StatusCode)+" "+text+"\r\n")
 
        // Process Body,ContentLength,Close,Trailer
-       tw, err := newTransferWriter(resp)
+       tw, err := newTransferWriter(r)
        if err != nil {
                return err
        }
@@ -217,7 +217,7 @@ func (resp *Response) Write(w io.Writer) error {
        }
 
        // Rest of header
-       err = resp.Header.WriteSubset(w, respExcludeHeader)
+       err = r.Header.WriteSubset(w, respExcludeHeader)
        if err != nil {
                return err
        }
index 147c216ec78744a1dd1036a3fed0fb676806a519..e2860c3edcf55fbd9eaa0cf80637716fa8517fd3 100644 (file)
@@ -504,8 +504,9 @@ func Test304Responses(t *testing.T) {
 }
 
 // TestHeadResponses verifies that responses to HEAD requests don't
-// declare that they're chunking in their response headers and aren't
-// allowed to produce output.
+// declare that they're chunking in their response headers, aren't
+// allowed to produce output, and don't set a Content-Type since
+// the real type of the body data cannot be inferred.
 func TestHeadResponses(t *testing.T) {
        ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
                _, err := w.Write([]byte("Ignored body"))
@@ -527,6 +528,10 @@ func TestHeadResponses(t *testing.T) {
        if len(res.TransferEncoding) > 0 {
                t.Errorf("expected no TransferEncoding; got %v", res.TransferEncoding)
        }
+       ct := res.Header.Get("Content-Type")
+       if ct != "" {
+               t.Errorf("expected no Content-Type; got %s", ct)
+       }
        body, err := ioutil.ReadAll(res.Body)
        if err != nil {
                t.Error(err)
index bad3bcb28969c17d65e776897b00380a3d27cd89..288539ba5760745a5f0b50dc45905a57675acb2b 100644 (file)
@@ -341,7 +341,7 @@ func (w *response) WriteHeader(code int) {
                }
        } else {
                // If no content type, apply sniffing algorithm to body.
-               if w.header.Get("Content-Type") == "" {
+               if w.header.Get("Content-Type") == "" && w.req.Method != "HEAD" {
                        w.needSniff = true
                }
        }
@@ -1078,8 +1078,8 @@ func ListenAndServeTLS(addr string, certFile string, keyFile string, handler Han
 // of the server's certificate followed by the CA's certificate.
 //
 // If srv.Addr is blank, ":https" is used.
-func (s *Server) ListenAndServeTLS(certFile, keyFile string) error {
-       addr := s.Addr
+func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
+       addr := srv.Addr
        if addr == "" {
                addr = ":https"
        }
@@ -1101,7 +1101,7 @@ func (s *Server) ListenAndServeTLS(certFile, keyFile string) error {
        }
 
        tlsListener := tls.NewListener(conn, config)
-       return s.Serve(tlsListener)
+       return srv.Serve(tlsListener)
 }
 
 // TimeoutHandler returns a Handler that runs h with the given time limit.
index 4de070f01f10d806c71db938b6d2a6ee80ed6b2b..693215edd4fcbce040a10b517a29e1dc4b58bc20 100644 (file)
@@ -535,7 +535,9 @@ func (pc *persistConn) readLoop() {
                }
                resp, err := ReadResponse(pc.br, rc.req)
 
-               if err == nil {
+               if err != nil {
+                       pc.close()
+               } else {
                        hasBody := rc.req.Method != "HEAD" && resp.ContentLength != 0
                        if rc.addedGzip && hasBody && resp.Header.Get("Content-Encoding") == "gzip" {
                                resp.Header.Del("Content-Encoding")
index 321da52e2781ab2b40bc08ebe8e6b89ae26e147f..caf81d6e46b28b853627b19fa467969557273568 100644 (file)
@@ -441,7 +441,11 @@ func TestRoundTripGzip(t *testing.T) {
                }
                if accept == "gzip" {
                        rw.Header().Set("Content-Encoding", "gzip")
-                       gz, _ := gzip.NewWriter(rw)
+                       gz, err := gzip.NewWriter(rw)
+                       if err != nil {
+                               t.Errorf("gzip NewWriter: %v", err)
+                               return
+                       }
                        gz.Write([]byte(responseBody))
                        gz.Close()
                } else {
@@ -460,7 +464,11 @@ func TestRoundTripGzip(t *testing.T) {
                res, err := DefaultTransport.RoundTrip(req)
                var body []byte
                if test.compressed {
-                       gzip, _ := gzip.NewReader(res.Body)
+                       gzip, err := gzip.NewReader(res.Body)
+                       if err != nil {
+                               t.Errorf("%d. gzip NewReader: %v", i, err)
+                               continue
+                       }
                        body, err = ioutil.ReadAll(gzip)
                        res.Body.Close()
                } else {
index 907f80a80f3118522bf0cc16a0dd1113f31919c1..7f090d8d40699323f6dc590866312bd073e38e0a 100644 (file)
@@ -15,11 +15,9 @@ import (
 )
 
 // If the ifindex is zero, interfaceTable returns mappings of all
-// network interfaces.  Otheriwse it returns a mapping of a specific
+// network interfaces.  Otherwise it returns a mapping of a specific
 // interface.
 func interfaceTable(ifindex int) ([]Interface, error) {
-       var ift []Interface
-
        tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex)
        if err != nil {
                return nil, os.NewSyscallError("route rib", err)
@@ -30,6 +28,7 @@ func interfaceTable(ifindex int) ([]Interface, error) {
                return nil, os.NewSyscallError("route message", err)
        }
 
+       var ift []Interface
        for _, m := range msgs {
                switch v := m.(type) {
                case *syscall.InterfaceMessage:
@@ -42,18 +41,16 @@ func interfaceTable(ifindex int) ([]Interface, error) {
                        }
                }
        }
-
        return ift, nil
 }
 
 func newLink(m *syscall.InterfaceMessage) ([]Interface, error) {
-       var ift []Interface
-
        sas, err := syscall.ParseRoutingSockaddr(m)
        if err != nil {
                return nil, os.NewSyscallError("route sockaddr", err)
        }
 
+       var ift []Interface
        for _, s := range sas {
                switch v := s.(type) {
                case *syscall.SockaddrDatalink:
@@ -75,7 +72,6 @@ func newLink(m *syscall.InterfaceMessage) ([]Interface, error) {
                        ift = append(ift, ifi)
                }
        }
-
        return ift, nil
 }
 
@@ -103,8 +99,6 @@ func linkFlags(rawFlags int32) Flags {
 // for all network interfaces.  Otherwise it returns addresses
 // for a specific interface.
 func interfaceAddrTable(ifindex int) ([]Addr, error) {
-       var ifat []Addr
-
        tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex)
        if err != nil {
                return nil, os.NewSyscallError("route rib", err)
@@ -115,6 +109,7 @@ func interfaceAddrTable(ifindex int) ([]Addr, error) {
                return nil, os.NewSyscallError("route message", err)
        }
 
+       var ifat []Addr
        for _, m := range msgs {
                switch v := m.(type) {
                case *syscall.InterfaceAddrMessage:
@@ -127,18 +122,16 @@ func interfaceAddrTable(ifindex int) ([]Addr, error) {
                        }
                }
        }
-
        return ifat, nil
 }
 
 func newAddr(m *syscall.InterfaceAddrMessage) (Addr, error) {
-       ifa := &IPNet{}
-
        sas, err := syscall.ParseRoutingSockaddr(m)
        if err != nil {
                return nil, os.NewSyscallError("route sockaddr", err)
        }
 
+       ifa := &IPNet{}
        for i, s := range sas {
                switch v := s.(type) {
                case *syscall.SockaddrInet4:
@@ -166,6 +159,5 @@ func newAddr(m *syscall.InterfaceAddrMessage) (Addr, error) {
                        }
                }
        }
-
        return ifa, nil
 }
index 2da447adc8438ed4ee6fb997d3a6dbbdc02bb321..0b5fb5fb9da11b7b3abfaa659b9f5a3ec0de70de 100644 (file)
@@ -15,23 +15,17 @@ import (
 // addresses for all network interfaces.  Otherwise it returns
 // addresses for a specific interface.
 func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
-       var (
-               tab   []byte
-               e     error
-               msgs  []syscall.RoutingMessage
-               ifmat []Addr
-       )
-
-       tab, e = syscall.RouteRIB(syscall.NET_RT_IFLIST2, ifindex)
-       if e != nil {
-               return nil, os.NewSyscallError("route rib", e)
+       tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST2, ifindex)
+       if err != nil {
+               return nil, os.NewSyscallError("route rib", err)
        }
 
-       msgs, e = syscall.ParseRoutingMessage(tab)
-       if e != nil {
-               return nil, os.NewSyscallError("route message", e)
+       msgs, err := syscall.ParseRoutingMessage(tab)
+       if err != nil {
+               return nil, os.NewSyscallError("route message", err)
        }
 
+       var ifmat []Addr
        for _, m := range msgs {
                switch v := m.(type) {
                case *syscall.InterfaceMulticastAddrMessage:
@@ -44,18 +38,16 @@ func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
                        }
                }
        }
-
        return ifmat, nil
 }
 
 func newMulticastAddr(m *syscall.InterfaceMulticastAddrMessage) ([]Addr, error) {
-       var ifmat []Addr
-
-       sas, e := syscall.ParseRoutingSockaddr(m)
-       if e != nil {
-               return nil, os.NewSyscallError("route sockaddr", e)
+       sas, err := syscall.ParseRoutingSockaddr(m)
+       if err != nil {
+               return nil, os.NewSyscallError("route sockaddr", err)
        }
 
+       var ifmat []Addr
        for _, s := range sas {
                switch v := s.(type) {
                case *syscall.SockaddrInet4:
@@ -75,6 +67,5 @@ func newMulticastAddr(m *syscall.InterfaceMulticastAddrMessage) ([]Addr, error)
                        ifmat = append(ifmat, ifma.toAddr())
                }
        }
-
        return ifmat, nil
 }
index a12877e251b0cb35950f78dae0791acf8d4bf8ad..3cba28fc6961d896d5cac4b2d1aa19c553c7ab0b 100644 (file)
@@ -15,23 +15,17 @@ import (
 // addresses for all network interfaces.  Otherwise it returns
 // addresses for a specific interface.
 func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
-       var (
-               tab   []byte
-               e     error
-               msgs  []syscall.RoutingMessage
-               ifmat []Addr
-       )
-
-       tab, e = syscall.RouteRIB(syscall.NET_RT_IFMALIST, ifindex)
-       if e != nil {
-               return nil, os.NewSyscallError("route rib", e)
+       tab, err := syscall.RouteRIB(syscall.NET_RT_IFMALIST, ifindex)
+       if err != nil {
+               return nil, os.NewSyscallError("route rib", err)
        }
 
-       msgs, e = syscall.ParseRoutingMessage(tab)
-       if e != nil {
-               return nil, os.NewSyscallError("route message", e)
+       msgs, err := syscall.ParseRoutingMessage(tab)
+       if err != nil {
+               return nil, os.NewSyscallError("route message", err)
        }
 
+       var ifmat []Addr
        for _, m := range msgs {
                switch v := m.(type) {
                case *syscall.InterfaceMulticastAddrMessage:
@@ -44,18 +38,16 @@ func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
                        }
                }
        }
-
        return ifmat, nil
 }
 
 func newMulticastAddr(m *syscall.InterfaceMulticastAddrMessage) ([]Addr, error) {
-       var ifmat []Addr
-
-       sas, e := syscall.ParseRoutingSockaddr(m)
-       if e != nil {
-               return nil, os.NewSyscallError("route sockaddr", e)
+       sas, err := syscall.ParseRoutingSockaddr(m)
+       if err != nil {
+               return nil, os.NewSyscallError("route sockaddr", err)
        }
 
+       var ifmat []Addr
        for _, s := range sas {
                switch v := s.(type) {
                case *syscall.SockaddrInet4:
@@ -75,6 +67,5 @@ func newMulticastAddr(m *syscall.InterfaceMulticastAddrMessage) ([]Addr, error)
                        ifmat = append(ifmat, ifma.toAddr())
                }
        }
-
        return ifmat, nil
 }
index c0887c57efeeb2b2e3e123a8eace09132844caf4..21038c629b13e42e1e1e52bbdf87e78eee1f89ec 100644 (file)
@@ -17,8 +17,6 @@ import (
 // network interfaces.  Otheriwse it returns a mapping of a specific
 // interface.
 func interfaceTable(ifindex int) ([]Interface, error) {
-       var ift []Interface
-
        tab, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)
        if err != nil {
                return nil, os.NewSyscallError("netlink rib", err)
@@ -29,6 +27,7 @@ func interfaceTable(ifindex int) ([]Interface, error) {
                return nil, os.NewSyscallError("netlink message", err)
        }
 
+       var ift []Interface
        for _, m := range msgs {
                switch m.Header.Type {
                case syscall.NLMSG_DONE:
@@ -45,7 +44,6 @@ func interfaceTable(ifindex int) ([]Interface, error) {
                        }
                }
        }
-
 done:
        return ift, nil
 }
@@ -111,13 +109,11 @@ func interfaceAddrTable(ifindex int) ([]Addr, error) {
        if err != nil {
                return nil, err
        }
-
        return ifat, nil
 }
 
 func addrTable(msgs []syscall.NetlinkMessage, ifindex int) ([]Addr, error) {
        var ifat []Addr
-
        for _, m := range msgs {
                switch m.Header.Type {
                case syscall.NLMSG_DONE:
@@ -133,7 +129,6 @@ func addrTable(msgs []syscall.NetlinkMessage, ifindex int) ([]Addr, error) {
                        }
                }
        }
-
 done:
        return ifat, nil
 }
@@ -165,32 +160,28 @@ func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
                err error
                ifi *Interface
        )
-
        if ifindex > 0 {
                ifi, err = InterfaceByIndex(ifindex)
                if err != nil {
                        return nil, err
                }
        }
-
        ifmat4 := parseProcNetIGMP(ifi)
        ifmat6 := parseProcNetIGMP6(ifi)
-
        return append(ifmat4, ifmat6...), nil
 }
 
 func parseProcNetIGMP(ifi *Interface) []Addr {
-       var (
-               ifmat []Addr
-               name  string
-       )
-
        fd, err := open("/proc/net/igmp")
        if err != nil {
                return nil
        }
        defer fd.close()
 
+       var (
+               ifmat []Addr
+               name  string
+       )
        fd.readLine() // skip first line
        b := make([]byte, IPv4len)
        for l, ok := fd.readLine(); ok; l, ok = fd.readLine() {
@@ -206,19 +197,17 @@ func parseProcNetIGMP(ifi *Interface) []Addr {
                        name = f[1]
                }
        }
-
        return ifmat
 }
 
 func parseProcNetIGMP6(ifi *Interface) []Addr {
-       var ifmat []Addr
-
        fd, err := open("/proc/net/igmp6")
        if err != nil {
                return nil
        }
        defer fd.close()
 
+       var ifmat []Addr
        b := make([]byte, IPv6len)
        for l, ok := fd.readLine(); ok; l, ok = fd.readLine() {
                f := getFields(l)
@@ -229,6 +218,5 @@ func parseProcNetIGMP6(ifi *Interface) []Addr {
 
                }
        }
-
        return ifmat
 }
index add3dd3b9d9216fa510456cd1dff607219856f1f..d0c97532699bd411a7a65a3c522cda5ae937d087 100644 (file)
@@ -25,31 +25,31 @@ func getAdapterList() (*syscall.IpAdapterInfo, error) {
        b := make([]byte, 1000)
        l := uint32(len(b))
        a := (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0]))
-       e := syscall.GetAdaptersInfo(a, &l)
-       if e == syscall.ERROR_BUFFER_OVERFLOW {
+       err := syscall.GetAdaptersInfo(a, &l)
+       if err == syscall.ERROR_BUFFER_OVERFLOW {
                b = make([]byte, l)
                a = (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0]))
-               e = syscall.GetAdaptersInfo(a, &l)
+               err = syscall.GetAdaptersInfo(a, &l)
        }
-       if e != nil {
-               return nil, os.NewSyscallError("GetAdaptersInfo", e)
+       if err != nil {
+               return nil, os.NewSyscallError("GetAdaptersInfo", err)
        }
        return a, nil
 }
 
 func getInterfaceList() ([]syscall.InterfaceInfo, error) {
-       s, e := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP)
-       if e != nil {
-               return nil, os.NewSyscallError("Socket", e)
+       s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP)
+       if err != nil {
+               return nil, os.NewSyscallError("Socket", err)
        }
        defer syscall.Closesocket(s)
 
        ii := [20]syscall.InterfaceInfo{}
        ret := uint32(0)
        size := uint32(unsafe.Sizeof(ii))
-       e = syscall.WSAIoctl(s, syscall.SIO_GET_INTERFACE_LIST, nil, 0, (*byte)(unsafe.Pointer(&ii[0])), size, &ret, nil, 0)
-       if e != nil {
-               return nil, os.NewSyscallError("WSAIoctl", e)
+       err = syscall.WSAIoctl(s, syscall.SIO_GET_INTERFACE_LIST, nil, 0, (*byte)(unsafe.Pointer(&ii[0])), size, &ret, nil, 0)
+       if err != nil {
+               return nil, os.NewSyscallError("WSAIoctl", err)
        }
        c := ret / uint32(unsafe.Sizeof(ii[0]))
        return ii[:c-1], nil
@@ -59,14 +59,14 @@ func getInterfaceList() ([]syscall.InterfaceInfo, error) {
 // network interfaces.  Otheriwse it returns a mapping of a specific
 // interface.
 func interfaceTable(ifindex int) ([]Interface, error) {
-       ai, e := getAdapterList()
-       if e != nil {
-               return nil, e
+       ai, err := getAdapterList()
+       if err != nil {
+               return nil, err
        }
 
-       ii, e := getInterfaceList()
-       if e != nil {
-               return nil, e
+       ii, err := getInterfaceList()
+       if err != nil {
+               return nil, err
        }
 
        var ift []Interface
@@ -130,9 +130,9 @@ func interfaceTable(ifindex int) ([]Interface, error) {
 // for all network interfaces.  Otherwise it returns addresses
 // for a specific interface.
 func interfaceAddrTable(ifindex int) ([]Addr, error) {
-       ai, e := getAdapterList()
-       if e != nil {
-               return nil, e
+       ai, err := getAdapterList()
+       if err != nil {
+               return nil, err
        }
 
        var ifat []Addr
index 859153c2aad6449d6757bf3bf49434e251863db2..382a4402770c29ed561400885087114eb9e4429b 100644 (file)
@@ -15,17 +15,17 @@ import (
 // interfaces for IP network connections.
 type IPConn bool
 
-// SetDeadline implements the net.Conn SetDeadline method.
+// SetDeadline implements the Conn SetDeadline method.
 func (c *IPConn) SetDeadline(t time.Time) error {
        return os.EPLAN9
 }
 
-// SetReadDeadline implements the net.Conn SetReadDeadline method.
+// SetReadDeadline implements the Conn SetReadDeadline method.
 func (c *IPConn) SetReadDeadline(t time.Time) error {
        return os.EPLAN9
 }
 
-// SetWriteDeadline implements the net.Conn SetWriteDeadline method.
+// SetWriteDeadline implements the Conn SetWriteDeadline method.
 func (c *IPConn) SetWriteDeadline(t time.Time) error {
        return os.EPLAN9
 }
index 9234f5aff65127391f39593980d13a0f05c29dc0..bfbce18a4147f432a3acbe0a2a5163589898f77b 100644 (file)
@@ -99,16 +99,12 @@ func JoinHostPort(host, port string) string {
 
 // Convert "host:port" into IP address and port.
 func hostPortToIP(net, hostport string) (ip IP, iport int, err error) {
-       var (
-               addr IP
-               p, i int
-               ok   bool
-       )
        host, port, err := SplitHostPort(hostport)
        if err != nil {
-               goto Error
+               return nil, 0, err
        }
 
+       var addr IP
        if host != "" {
                // Try as an IP address.
                addr = ParseIP(host)
@@ -121,34 +117,29 @@ func hostPortToIP(net, hostport string) (ip IP, iport int, err error) {
                                filter = ipv6only
                        }
                        // Not an IP address.  Try as a DNS name.
-                       addrs, err1 := LookupHost(host)
-                       if err1 != nil {
-                               err = err1
-                               goto Error
+                       addrs, err := LookupHost(host)
+                       if err != nil {
+                               return nil, 0, err
                        }
                        addr = firstFavoriteAddr(filter, addrs)
                        if addr == nil {
                                // should not happen
-                               err = &AddrError{"LookupHost returned no suitable address", addrs[0]}
-                               goto Error
+                               return nil, 0, &AddrError{"LookupHost returned no suitable address", addrs[0]}
                        }
                }
        }
 
-       p, i, ok = dtoi(port, 0)
+       p, i, ok := dtoi(port, 0)
        if !ok || i != len(port) {
                p, err = LookupPort(net, port)
                if err != nil {
-                       goto Error
+                       return nil, 0, err
                }
        }
        if p < 0 || p > 0xFFFF {
-               err = &AddrError{"invalid port", port}
-               goto Error
+               return nil, 0, &AddrError{"invalid port", port}
        }
 
        return addr, p, nil
 
-Error:
-       return nil, 0, err
 }
index 09d8d6b4e040de926bda0b45ac65e30b5972388f..597b1277544791d1e9ab80a3ff6dac4366029f23 100644 (file)
@@ -22,33 +22,22 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
 
 // parsePlan9Addr parses address of the form [ip!]port (e.g. 127.0.0.1!80).
 func parsePlan9Addr(s string) (ip IP, iport int, err error) {
-       var (
-               addr IP
-               p, i int
-               ok   bool
-       )
-       addr = IPv4zero // address contains port only
-       i = byteIndex(s, '!')
+       addr := IPv4zero // address contains port only
+       i := byteIndex(s, '!')
        if i >= 0 {
                addr = ParseIP(s[:i])
                if addr == nil {
-                       err = errors.New("net: parsing IP failed")
-                       goto Error
+                       return nil, 0, errors.New("net: parsing IP failed")
                }
        }
-       p, _, ok = dtoi(s[i+1:], 0)
+       p, _, ok := dtoi(s[i+1:], 0)
        if !ok {
-               err = errors.New("net: parsing port failed")
-               goto Error
+               return nil, 0, errors.New("net: parsing port failed")
        }
        if p < 0 || p > 0xFFFF {
-               err = &AddrError{"invalid port", string(p)}
-               goto Error
+               return nil, 0, &AddrError{"invalid port", string(p)}
        }
        return addr, p, nil
-
-Error:
-       return nil, 0, err
 }
 
 func readPlan9Addr(proto, filename string) (addr Addr, err error) {
@@ -91,7 +80,7 @@ func (c *plan9Conn) ok() bool { return c != nil && c.ctl != nil }
 
 // Implementation of the Conn interface - see Conn for documentation.
 
-// Read implements the net.Conn Read method.
+// Read implements the Conn Read method.
 func (c *plan9Conn) Read(b []byte) (n int, err error) {
        if !c.ok() {
                return 0, os.EINVAL
@@ -110,7 +99,7 @@ func (c *plan9Conn) Read(b []byte) (n int, err error) {
        return
 }
 
-// Write implements the net.Conn Write method.
+// Write implements the Conn Write method.
 func (c *plan9Conn) Write(b []byte) (n int, err error) {
        if !c.ok() {
                return 0, os.EINVAL
@@ -157,17 +146,17 @@ func (c *plan9Conn) RemoteAddr() Addr {
        return c.raddr
 }
 
-// SetDeadline implements the net.Conn SetDeadline method.
+// SetDeadline implements the Conn SetDeadline method.
 func (c *plan9Conn) SetDeadline(t time.Time) error {
        return os.EPLAN9
 }
 
-// SetReadDeadline implements the net.Conn SetReadDeadline method.
+// SetReadDeadline implements the Conn SetReadDeadline method.
 func (c *plan9Conn) SetReadDeadline(t time.Time) error {
        return os.EPLAN9
 }
 
-// SetWriteDeadline implements the net.Conn SetWriteDeadline method.
+// SetWriteDeadline implements the Conn SetWriteDeadline method.
 func (c *plan9Conn) SetWriteDeadline(t time.Time) error {
        return os.EPLAN9
 }
index dfe2ff6f1fa762447c9616fb51b634b31ec1f739..99783e975679634bea09e95ce99c7996d23749d4 100644 (file)
@@ -21,9 +21,9 @@ var (
 func lookupProtocol(name string) (proto int, err error) {
        protoentLock.Lock()
        defer protoentLock.Unlock()
-       p, e := syscall.GetProtoByName(name)
-       if e != nil {
-               return 0, os.NewSyscallError("GetProtoByName", e)
+       p, err := syscall.GetProtoByName(name)
+       if err != nil {
+               return 0, os.NewSyscallError("GetProtoByName", err)
        }
        return int(p.Proto), nil
 }
@@ -43,9 +43,9 @@ func lookupHost(name string) (addrs []string, err error) {
 func lookupIP(name string) (addrs []IP, err error) {
        hostentLock.Lock()
        defer hostentLock.Unlock()
-       h, e := syscall.GetHostByName(name)
-       if e != nil {
-               return nil, os.NewSyscallError("GetHostByName", e)
+       h, err := syscall.GetHostByName(name)
+       if err != nil {
+               return nil, os.NewSyscallError("GetHostByName", err)
        }
        switch h.AddrType {
        case syscall.AF_INET:
@@ -70,9 +70,9 @@ func lookupPort(network, service string) (port int, err error) {
        }
        serventLock.Lock()
        defer serventLock.Unlock()
-       s, e := syscall.GetServByName(service, network)
-       if e != nil {
-               return 0, os.NewSyscallError("GetServByName", e)
+       s, err := syscall.GetServByName(service, network)
+       if err != nil {
+               return 0, os.NewSyscallError("GetServByName", err)
        }
        return int(syscall.Ntohs(s.Port)), nil
 }
index 183d5a8abaa837c9a136525098442614709896ad..bf0fe4d8d0a20e28334836a3a7fae487bc8d7169 100644 (file)
@@ -5,47 +5,40 @@
 package net
 
 import (
-       "flag"
        "os"
        "runtime"
        "testing"
 )
 
-var multicast = flag.Bool("multicast", false, "enable multicast tests")
-
-var multicastUDPTests = []struct {
+var listenMulticastUDPTests = []struct {
        net   string
-       laddr IP
-       gaddr IP
+       gaddr *UDPAddr
        flags Flags
        ipv6  bool
 }{
        // cf. RFC 4727: Experimental Values in IPv4, IPv6, ICMPv4, ICMPv6, UDP, and TCP Headers
-       {"udp", IPv4zero, IPv4(224, 0, 0, 254), (FlagUp | FlagLoopback), false},
-       {"udp4", IPv4zero, IPv4(224, 0, 0, 254), (FlagUp | FlagLoopback), false},
-       {"udp", IPv6unspecified, ParseIP("ff0e::114"), (FlagUp | FlagLoopback), true},
-       {"udp6", IPv6unspecified, ParseIP("ff01::114"), (FlagUp | FlagLoopback), true},
-       {"udp6", IPv6unspecified, ParseIP("ff02::114"), (FlagUp | FlagLoopback), true},
-       {"udp6", IPv6unspecified, ParseIP("ff04::114"), (FlagUp | FlagLoopback), true},
-       {"udp6", IPv6unspecified, ParseIP("ff05::114"), (FlagUp | FlagLoopback), true},
-       {"udp6", IPv6unspecified, ParseIP("ff08::114"), (FlagUp | FlagLoopback), true},
-       {"udp6", IPv6unspecified, ParseIP("ff0e::114"), (FlagUp | FlagLoopback), true},
+       {"udp", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, FlagUp | FlagLoopback, false},
+       {"udp4", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, FlagUp | FlagLoopback, false},
+       {"udp", &UDPAddr{ParseIP("ff0e::114"), 12345}, FlagUp | FlagLoopback, true},
+       {"udp6", &UDPAddr{ParseIP("ff01::114"), 12345}, FlagUp | FlagLoopback, true},
+       {"udp6", &UDPAddr{ParseIP("ff02::114"), 12345}, FlagUp | FlagLoopback, true},
+       {"udp6", &UDPAddr{ParseIP("ff04::114"), 12345}, FlagUp | FlagLoopback, true},
+       {"udp6", &UDPAddr{ParseIP("ff05::114"), 12345}, FlagUp | FlagLoopback, true},
+       {"udp6", &UDPAddr{ParseIP("ff08::114"), 12345}, FlagUp | FlagLoopback, true},
+       {"udp6", &UDPAddr{ParseIP("ff0e::114"), 12345}, FlagUp | FlagLoopback, true},
 }
 
-func TestMulticastUDP(t *testing.T) {
-       if runtime.GOOS == "plan9" || runtime.GOOS == "windows" {
-               return
-       }
-       if !*multicast {
-               t.Logf("test disabled; use --multicast to enable")
+func TestListenMulticastUDP(t *testing.T) {
+       switch runtime.GOOS {
+       case "netbsd", "openbsd", "plan9", "windows":
                return
+       case "linux":
+               if runtime.GOARCH == "arm" {
+                       return
+               }
        }
 
-       for _, tt := range multicastUDPTests {
-               var (
-                       ifi   *Interface
-                       found bool
-               )
+       for _, tt := range listenMulticastUDPTests {
                if tt.ipv6 && (!supportsIPv6 || os.Getuid() != 0) {
                        continue
                }
@@ -53,6 +46,7 @@ func TestMulticastUDP(t *testing.T) {
                if err != nil {
                        t.Fatalf("Interfaces failed: %v", err)
                }
+               var ifi *Interface
                for _, x := range ift {
                        if x.Flags&tt.flags == tt.flags {
                                ifi = &x
@@ -63,14 +57,11 @@ func TestMulticastUDP(t *testing.T) {
                        t.Logf("an appropriate multicast interface not found")
                        return
                }
-               c, err := ListenUDP(tt.net, &UDPAddr{IP: tt.laddr})
+               c, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr)
                if err != nil {
-                       t.Fatalf("ListenUDP failed: %v", err)
-               }
-               defer c.Close()
-               if err := c.JoinGroup(ifi, tt.gaddr); err != nil {
-                       t.Fatalf("JoinGroup failed: %v", err)
+                       t.Fatalf("ListenMulticastUDP failed: %v", err)
                }
+               defer c.Close() // test to listen concurrently across multiple listeners
                if !tt.ipv6 {
                        testIPv4MulticastSocketOptions(t, c.fd, ifi)
                } else {
@@ -80,8 +71,9 @@ func TestMulticastUDP(t *testing.T) {
                if err != nil {
                        t.Fatalf("MulticastAddrs failed: %v", err)
                }
+               var found bool
                for _, ifma := range ifmat {
-                       if ifma.(*IPAddr).IP.Equal(tt.gaddr) {
+                       if ifma.(*IPAddr).IP.Equal(tt.gaddr.IP) {
                                found = true
                                break
                        }
@@ -89,23 +81,16 @@ func TestMulticastUDP(t *testing.T) {
                if !found {
                        t.Fatalf("%q not found in RIB", tt.gaddr.String())
                }
-               if err := c.LeaveGroup(ifi, tt.gaddr); err != nil {
-                       t.Fatalf("LeaveGroup failed: %v", err)
-               }
        }
 }
 
-func TestSimpleMulticastUDP(t *testing.T) {
-       if runtime.GOOS == "plan9" {
-               return
-       }
-       if !*multicast {
-               t.Logf("test disabled; use --multicast to enable")
+func TestSimpleListenMulticastUDP(t *testing.T) {
+       switch runtime.GOOS {
+       case "plan9":
                return
        }
 
-       for _, tt := range multicastUDPTests {
-               var ifi *Interface
+       for _, tt := range listenMulticastUDPTests {
                if tt.ipv6 {
                        continue
                }
@@ -114,6 +99,7 @@ func TestSimpleMulticastUDP(t *testing.T) {
                if err != nil {
                        t.Fatalf("Interfaces failed: %v", err)
                }
+               var ifi *Interface
                for _, x := range ift {
                        if x.Flags&tt.flags == tt.flags {
                                ifi = &x
@@ -124,17 +110,11 @@ func TestSimpleMulticastUDP(t *testing.T) {
                        t.Logf("an appropriate multicast interface not found")
                        return
                }
-               c, err := ListenUDP(tt.net, &UDPAddr{IP: tt.laddr})
+               c, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr)
                if err != nil {
-                       t.Fatalf("ListenUDP failed: %v", err)
-               }
-               defer c.Close()
-               if err := c.JoinGroup(ifi, tt.gaddr); err != nil {
-                       t.Fatalf("JoinGroup failed: %v", err)
-               }
-               if err := c.LeaveGroup(ifi, tt.gaddr); err != nil {
-                       t.Fatalf("LeaveGroup failed: %v", err)
+                       t.Fatalf("ListenMulticastUDP failed: %v", err)
                }
+               c.Close()
        }
 }
 
index 609fee242d0dbacdd77655b206888a2bbe707ef1..79d36a2a8136d00a2d5f6290e95e18cc8e9e5e28 100644 (file)
@@ -23,12 +23,12 @@ type Addr interface {
 // Conn is a generic stream-oriented network connection.
 type Conn interface {
        // Read reads data from the connection.
-       // Read can be made to time out and return a net.Error with Timeout() == true
+       // Read can be made to time out and return a Error with Timeout() == true
        // after a fixed time limit; see SetDeadline and SetReadDeadline.
        Read(b []byte) (n int, err error)
 
        // Write writes data to the connection.
-       // Write can be made to time out and return a net.Error with Timeout() == true
+       // Write can be made to time out and return a Error with Timeout() == true
        // after a fixed time limit; see SetDeadline and SetWriteDeadline.
        Write(b []byte) (n int, err error)
 
@@ -201,3 +201,15 @@ type UnknownNetworkError string
 func (e UnknownNetworkError) Error() string   { return "unknown network " + string(e) }
 func (e UnknownNetworkError) Temporary() bool { return false }
 func (e UnknownNetworkError) Timeout() bool   { return false }
+
+// DNSConfigError represents an error reading the machine's DNS configuration.
+type DNSConfigError struct {
+       Err error
+}
+
+func (e *DNSConfigError) Error() string {
+       return "error reading DNS config: " + e.Err.Error()
+}
+
+func (e *DNSConfigError) Timeout() bool   { return false }
+func (e *DNSConfigError) Temporary() bool { return false }
index d09ebf06f132f43a4ece72498d2e9f1b70e16ef8..1bc997754bb37ac6311e244d248c2b8f6af9615c 100644 (file)
@@ -71,15 +71,15 @@ func TestDialError(t *testing.T) {
                return
        }
        for i, tt := range dialErrorTests {
-               c, e := Dial(tt.Net, tt.Raddr)
+               c, err := Dial(tt.Net, tt.Raddr)
                if c != nil {
                        c.Close()
                }
-               if e == nil {
+               if err == nil {
                        t.Errorf("#%d: nil error, want match for %#q", i, tt.Pattern)
                        continue
                }
-               s := e.Error()
+               s := err.Error()
                match, _ := regexp.MatchString(tt.Pattern, s)
                if !match {
                        t.Errorf("#%d: %q, want match for %#q", i, s, tt.Pattern)
@@ -111,16 +111,16 @@ var revAddrTests = []struct {
 
 func TestReverseAddress(t *testing.T) {
        for i, tt := range revAddrTests {
-               a, e := reverseaddr(tt.Addr)
-               if len(tt.ErrPrefix) > 0 && e == nil {
+               a, err := reverseaddr(tt.Addr)
+               if len(tt.ErrPrefix) > 0 && err == nil {
                        t.Errorf("#%d: expected %q, got <nil> (error)", i, tt.ErrPrefix)
                        continue
                }
-               if len(tt.ErrPrefix) == 0 && e != nil {
-                       t.Errorf("#%d: expected <nil>, got %q (error)", i, e)
+               if len(tt.ErrPrefix) == 0 && err != nil {
+                       t.Errorf("#%d: expected <nil>, got %q (error)", i, err)
                }
-               if e != nil && e.(*DNSError).Err != tt.ErrPrefix {
-                       t.Errorf("#%d: expected %q, got %q (mismatched error)", i, tt.ErrPrefix, e.(*DNSError).Err)
+               if err != nil && err.(*DNSError).Err != tt.ErrPrefix {
+                       t.Errorf("#%d: expected %q, got %q (mismatched error)", i, tt.ErrPrefix, err.(*DNSError).Err)
                }
                if a != tt.Reverse {
                        t.Errorf("#%d: expected %q, got %q (reverse address)", i, tt.Reverse, a)
index a410bb6ce1f86c3ba435feb5dda0bf7cb9689026..06bc24cd8a23178df388cf27e1487daaa5eddcda 100644 (file)
@@ -36,7 +36,11 @@ func newPollServer() (s *pollServer, err error) {
        return s, nil
 
 Errno:
-       err = &os.PathError{"setnonblock", s.pr.Name(), err}
+       err = &os.PathError{
+               Op:   "setnonblock",
+               Path: s.pr.Name(),
+               Err:  err,
+       }
 Error:
        s.pr.Close()
        s.pw.Close()
index abc1e59cd510858c66b3c70ff33c7a9a2af09957..34f9ae317e28822925c6d94ee1279daa4849754e 100644 (file)
@@ -31,8 +31,7 @@ type Call struct {
        Args          interface{} // The argument to the function (*struct).
        Reply         interface{} // The reply from the function (*struct).
        Error         error       // After completion, the error status.
-       Done          chan *Call  // Strobes when call is complete; value is the error status.
-       seq           uint64
+       Done          chan *Call  // Strobes when call is complete.
 }
 
 // Client represents an RPC Client.
@@ -65,28 +64,33 @@ type ClientCodec interface {
        Close() error
 }
 
-func (client *Client) send(c *Call) {
+func (client *Client) send(call *Call) {
+       client.sending.Lock()
+       defer client.sending.Unlock()
+
        // Register this call.
        client.mutex.Lock()
        if client.shutdown {
-               c.Error = ErrShutdown
+               call.Error = ErrShutdown
                client.mutex.Unlock()
-               c.done()
+               call.done()
                return
        }
-       c.seq = client.seq
+       seq := client.seq
        client.seq++
-       client.pending[c.seq] = c
+       client.pending[seq] = call
        client.mutex.Unlock()
 
        // Encode and send the request.
-       client.sending.Lock()
-       defer client.sending.Unlock()
-       client.request.Seq = c.seq
-       client.request.ServiceMethod = c.ServiceMethod
-       if err := client.codec.WriteRequest(&client.request, c.Args); err != nil {
-               c.Error = err
-               c.done()
+       client.request.Seq = seq
+       client.request.ServiceMethod = call.ServiceMethod
+       err := client.codec.WriteRequest(&client.request, call.Args)
+       if err != nil {
+               client.mutex.Lock()
+               delete(client.pending, seq)
+               client.mutex.Unlock()
+               call.Error = err
+               call.done()
        }
 }
 
@@ -104,36 +108,39 @@ func (client *Client) input() {
                }
                seq := response.Seq
                client.mutex.Lock()
-               c := client.pending[seq]
+               call := client.pending[seq]
                delete(client.pending, seq)
                client.mutex.Unlock()
 
                if response.Error == "" {
-                       err = client.codec.ReadResponseBody(c.Reply)
+                       err = client.codec.ReadResponseBody(call.Reply)
                        if err != nil {
-                               c.Error = errors.New("reading body " + err.Error())
+                               call.Error = errors.New("reading body " + err.Error())
                        }
                } else {
                        // We've got an error response. Give this to the request;
                        // any subsequent requests will get the ReadResponseBody
                        // error if there is one.
-                       c.Error = ServerError(response.Error)
+                       call.Error = ServerError(response.Error)
                        err = client.codec.ReadResponseBody(nil)
                        if err != nil {
                                err = errors.New("reading error body: " + err.Error())
                        }
                }
-               c.done()
+               call.done()
        }
        // Terminate pending calls.
+       client.sending.Lock()
        client.mutex.Lock()
        client.shutdown = true
+       closing := client.closing
        for _, call := range client.pending {
                call.Error = err
                call.done()
        }
        client.mutex.Unlock()
-       if err != io.EOF || !client.closing {
+       client.sending.Unlock()
+       if err != io.EOF || !closing {
                log.Println("rpc: client protocol error:", err)
        }
 }
@@ -225,7 +232,12 @@ func DialHTTPPath(network, address, path string) (*Client, error) {
                err = errors.New("unexpected HTTP response: " + resp.Status)
        }
        conn.Close()
-       return nil, &net.OpError{"dial-http", network + " " + address, nil, err}
+       return nil, &net.OpError{
+               Op:   "dial-http",
+               Net:  network + " " + address,
+               Addr: nil,
+               Err:  err,
+       }
 }
 
 // Dial connects to an RPC server at the specified network address.
@@ -269,20 +281,12 @@ func (client *Client) Go(serviceMethod string, args interface{}, reply interface
                }
        }
        call.Done = done
-       if client.shutdown {
-               call.Error = ErrShutdown
-               call.done()
-               return call
-       }
        client.send(call)
        return call
 }
 
 // Call invokes the named function, waits for it to complete, and returns its error status.
 func (client *Client) Call(serviceMethod string, args interface{}, reply interface{}) error {
-       if client.shutdown {
-               return ErrShutdown
-       }
        call := <-client.Go(serviceMethod, args, reply, make(chan *Call, 1)).Done
        return call.Error
 }
index b05c63c0563d747cf4d6be5dc4c33b8d67183025..8cfa033ccc3be0adf8a62e712a86115a9f41371e 100644 (file)
@@ -442,8 +442,9 @@ func countMallocs(dial func() (*Client, error), t *testing.T) uint64 {
        }
        args := &Args{7, 8}
        reply := new(Reply)
-       runtime.UpdateMemStats()
-       mallocs := 0 - runtime.MemStats.Mallocs
+       memstats := new(runtime.MemStats)
+       runtime.ReadMemStats(memstats)
+       mallocs := 0 - memstats.Mallocs
        const count = 100
        for i := 0; i < count; i++ {
                err := client.Call("Arith.Add", args, reply)
@@ -454,8 +455,8 @@ func countMallocs(dial func() (*Client, error), t *testing.T) uint64 {
                        t.Errorf("Add: expected %d got %d", reply.C, args.A+args.B)
                }
        }
-       runtime.UpdateMemStats()
-       mallocs += runtime.MemStats.Mallocs
+       runtime.ReadMemStats(memstats)
+       mallocs += memstats.Mallocs
        return mallocs / count
 }
 
index e9ab066663ea8619993dbdde5ac288a8c2707952..7f51519b2ed13912407fd305a52f250e8c202503 100644 (file)
@@ -48,23 +48,23 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
                if int64(n) > remain {
                        n = int(remain)
                }
-               n, errno := syscall.Sendfile(dst, src, nil, n)
+               n, err1 := syscall.Sendfile(dst, src, nil, n)
                if n > 0 {
                        written += int64(n)
                        remain -= int64(n)
                }
-               if n == 0 && errno == nil {
+               if n == 0 && err1 == nil {
                        break
                }
-               if errno == syscall.EAGAIN && c.wdeadline >= 0 {
+               if err1 == syscall.EAGAIN && c.wdeadline >= 0 {
                        pollserver.WaitWrite(c)
                        continue
                }
-               if errno != nil {
+               if err1 != nil {
                        // This includes syscall.ENOSYS (no kernel
                        // support) and syscall.EINVAL (fd types which
                        // don't implement sendfile together)
-                       err = &OpError{"sendfile", c.net, c.raddr, errno}
+                       err = &OpError{"sendfile", c.net, c.raddr, err1}
                        break
                }
        }
index 8d935ffb7a1efb0bc1d73df1badaede5d2725f49..f600cc8648212182d99520f6464a2c2e7e248b51 100644 (file)
@@ -155,7 +155,7 @@ func (c *Client) Auth(a Auth) error {
                        // the last message isn't base64 because it isn't a challenge
                        msg = []byte(msg64)
                default:
-                       err = &textproto.Error{code, msg64}
+                       err = &textproto.Error{Code: code, Msg: msg64}
                }
                resp, err = a.Next(msg, code == 334)
                if err != nil {
index 867e328f12eb419a78d4f65e4d0798e7ab907d1d..70064c307ef36b5319d3a341c5829ecf318325b7 100644 (file)
@@ -10,7 +10,6 @@ package net
 
 import (
        "io"
-       "reflect"
        "syscall"
 )
 
@@ -28,9 +27,18 @@ func socket(net string, f, t, p int, la, ra syscall.Sockaddr, toAddr func(syscal
        syscall.CloseOnExec(s)
        syscall.ForkLock.RUnlock()
 
-       setDefaultSockopts(s, f, t)
+       err = setDefaultSockopts(s, f, t)
+       if err != nil {
+               closesocket(s)
+               return nil, err
+       }
 
        if la != nil {
+               la, err = listenerSockaddr(s, f, la, toAddr)
+               if err != nil {
+                       closesocket(s)
+                       return nil, err
+               }
                err = syscall.Bind(s, la)
                if err != nil {
                        closesocket(s)
@@ -61,14 +69,6 @@ func socket(net string, f, t, p int, la, ra syscall.Sockaddr, toAddr func(syscal
        return fd, nil
 }
 
-type UnknownSocketError struct {
-       sa syscall.Sockaddr
-}
-
-func (e *UnknownSocketError) Error() string {
-       return "unknown socket address type " + reflect.TypeOf(e.sa).String()
-}
-
 type writerOnly struct {
        io.Writer
 }
index 630a91ed9f670d06f35658264b2d248b2f3c9848..7c693a271f7898adf5475fe5977055a09127bfe5 100644 (file)
@@ -31,3 +31,27 @@ func maxListenerBacklog() int {
        }
        return int(n)
 }
+
+func listenerSockaddr(s, f int, la syscall.Sockaddr, toAddr func(syscall.Sockaddr) Addr) (syscall.Sockaddr, error) {
+       a := toAddr(la)
+       if a == nil {
+               return la, nil
+       }
+       switch v := a.(type) {
+       case *UDPAddr:
+               if v.IP.IsMulticast() {
+                       err := setDefaultMulticastSockopts(s)
+                       if err != nil {
+                               return nil, err
+                       }
+                       switch f {
+                       case syscall.AF_INET:
+                               v.IP = IPv4zero
+                       case syscall.AF_INET6:
+                               v.IP = IPv6unspecified
+                       }
+                       return v.sockaddr(f)
+               }
+       }
+       return la, nil
+}
index 2cbc34f24b38384482642ac59e397cd542d5463f..0743843bf2807421611f62a44fbf2404837128ce 100644 (file)
@@ -25,3 +25,27 @@ func maxListenerBacklog() int {
        }
        return n
 }
+
+func listenerSockaddr(s, f int, la syscall.Sockaddr, toAddr func(syscall.Sockaddr) Addr) (syscall.Sockaddr, error) {
+       a := toAddr(la)
+       if a == nil {
+               return la, nil
+       }
+       switch v := a.(type) {
+       case *UDPAddr:
+               if v.IP.IsMulticast() {
+                       err := setDefaultMulticastSockopts(s)
+                       if err != nil {
+                               return nil, err
+                       }
+                       switch f {
+                       case syscall.AF_INET:
+                               v.IP = IPv4zero
+                       case syscall.AF_INET6:
+                               v.IP = IPv6unspecified
+                       }
+                       return v.sockaddr(f)
+               }
+       }
+       return la, nil
+}
index 2d803de1fc180da2e93adaa87adfaec4aa93cb11..434122c9e46b9c572427b3a95bc356e5d7d87542 100644 (file)
@@ -12,3 +12,27 @@ func maxListenerBacklog() int {
        // TODO: Implement this
        return syscall.SOMAXCONN
 }
+
+func listenerSockaddr(s syscall.Handle, f int, la syscall.Sockaddr, toAddr func(syscall.Sockaddr) Addr) (syscall.Sockaddr, error) {
+       a := toAddr(la)
+       if a == nil {
+               return la, nil
+       }
+       switch v := a.(type) {
+       case *UDPAddr:
+               if v.IP.IsMulticast() {
+                       err := setDefaultMulticastSockopts(s)
+                       if err != nil {
+                               return nil, err
+                       }
+                       switch f {
+                       case syscall.AF_INET:
+                               v.IP = IPv4zero
+                       case syscall.AF_INET6:
+                               v.IP = IPv6unspecified
+                       }
+                       return v.sockaddr(f)
+               }
+       }
+       return la, nil
+}
index 3d0f8dd7a89622ecd6a72ca040b181b1c96b6d94..b5b75a2745ac80a609f42c04ccb6d49afcc06e7f 100644 (file)
@@ -135,8 +135,8 @@ func setWriteDeadline(fd *netFD, t time.Time) error {
 }
 
 func setDeadline(fd *netFD, t time.Time) error {
-       if e := setReadDeadline(fd, t); e != nil {
-               return e
+       if err := setReadDeadline(fd, t); err != nil {
+               return err
        }
        return setWriteDeadline(fd, t)
 }
index 2093e08127db5de47f40e16b3d9a015456af351c..bc764650627579600de41933879622883cec986d 100644 (file)
@@ -9,37 +9,55 @@
 package net
 
 import (
+       "os"
        "syscall"
 )
 
-func setDefaultSockopts(s, f, t int) {
+func setDefaultSockopts(s, f, t int) error {
        switch f {
        case syscall.AF_INET6:
                // Allow both IP versions even if the OS default is otherwise.
+               // Note that some operating systems never admit this option.
                syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
        }
 
        if f == syscall.AF_UNIX ||
                (f == syscall.AF_INET || f == syscall.AF_INET6) && t == syscall.SOCK_STREAM {
                // Allow reuse of recently-used addresses.
-               syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
+               err := syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
+               if err != nil {
+                       return os.NewSyscallError("setsockopt", err)
+               }
 
                // Allow reuse of recently-used ports.
                // This option is supported only in descendants of 4.4BSD,
                // to make an effective multicast application and an application
                // that requires quick draw possible.
-               syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEPORT, 1)
+               err = syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEPORT, 1)
+               if err != nil {
+                       return os.NewSyscallError("setsockopt", err)
+               }
        }
 
        // Allow broadcast.
-       syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)
+       err := syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)
+       if err != nil {
+               return os.NewSyscallError("setsockopt", err)
+       }
+
+       return nil
 }
 
-func setDefaultMulticastSockopts(fd *netFD) {
-       fd.incref()
-       defer fd.decref()
+func setDefaultMulticastSockopts(s int) error {
        // Allow multicast UDP and raw IP datagram sockets to listen
        // concurrently across multiple listeners.
-       syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
-       syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_REUSEPORT, 1)
+       err := syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
+       if err != nil {
+               return os.NewSyscallError("setsockopt", err)
+       }
+       err = syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEPORT, 1)
+       if err != nil {
+               return os.NewSyscallError("setsockopt", err)
+       }
+       return nil
 }
index 9dbb4e5dde48042e494e30f1f36cad6f9e79a922..67c1dc87a7a0099b0c09a530cccfa056a4ed2ef2 100644 (file)
@@ -7,31 +7,43 @@
 package net
 
 import (
+       "os"
        "syscall"
 )
 
-func setDefaultSockopts(s, f, t int) {
+func setDefaultSockopts(s, f, t int) error {
        switch f {
        case syscall.AF_INET6:
                // Allow both IP versions even if the OS default is otherwise.
+               // Note that some operating systems never admit this option.
                syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
        }
 
        if f == syscall.AF_UNIX ||
                (f == syscall.AF_INET || f == syscall.AF_INET6) && t == syscall.SOCK_STREAM {
                // Allow reuse of recently-used addresses.
-               syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
+               err := syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
+               if err != nil {
+                       return os.NewSyscallError("setsockopt", err)
+               }
+
        }
 
        // Allow broadcast.
-       syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)
+       err := syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)
+       if err != nil {
+               return os.NewSyscallError("setsockopt", err)
+       }
 
+       return nil
 }
 
-func setDefaultMulticastSockopts(fd *netFD) {
-       fd.incref()
-       defer fd.decref()
+func setDefaultMulticastSockopts(s int) error {
        // Allow multicast UDP and raw IP datagram sockets to listen
        // concurrently across multiple listeners.
-       syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
+       err := syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
+       if err != nil {
+               return os.NewSyscallError("setsockopt", err)
+       }
+       return nil
 }
index a7b5606d865f607390b4e81649f8607f97ace830..842bccc8f40fe92ae827868d6ed9267e41abb8f9 100644 (file)
@@ -7,13 +7,15 @@
 package net
 
 import (
+       "os"
        "syscall"
 )
 
-func setDefaultSockopts(s syscall.Handle, f, t int) {
+func setDefaultSockopts(s syscall.Handle, f, t int) error {
        switch f {
        case syscall.AF_INET6:
                // Allow both IP versions even if the OS default is otherwise.
+               // Note that some operating systems never admit this option.
                syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
        }
 
@@ -26,13 +28,15 @@ func setDefaultSockopts(s syscall.Handle, f, t int) {
 
        // Allow broadcast.
        syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)
-
+       return nil
 }
 
-func setDefaultMulticastSockopts(fd *netFD) {
-       fd.incref()
-       defer fd.decref()
+func setDefaultMulticastSockopts(s syscall.Handle) error {
        // Allow multicast UDP and raw IP datagram sockets to listen
        // concurrently across multiple listeners.
-       syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
+       err := syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
+       if err != nil {
+               return os.NewSyscallError("setsockopt", err)
+       }
+       return nil
 }
index 3320e76bda883b28b64e1ea615f9b46352c6ffe7..a8a9d1c2bfb4787501ebd3312de3806732a34397 100644 (file)
@@ -7,6 +7,7 @@
 package net
 
 import (
+       "os"
        "syscall"
 )
 
@@ -16,8 +17,19 @@ func ipv4MulticastInterface(fd *netFD) (*Interface, error) {
 }
 
 func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error {
-       // TODO: Implement this
-       return syscall.EWINDOWS
+       ip, err := interfaceToIPv4Addr(ifi)
+       if err != nil {
+               return os.NewSyscallError("setsockopt", err)
+       }
+       var x [4]byte
+       copy(x[:], ip.To4())
+       fd.incref()
+       defer fd.decref()
+       err = syscall.SetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, x)
+       if err != nil {
+               return os.NewSyscallError("setsockopt", err)
+       }
+       return nil
 }
 
 func ipv4MulticastTTL(fd *netFD) (int, error) {
@@ -26,8 +38,14 @@ func ipv4MulticastTTL(fd *netFD) (int, error) {
 }
 
 func setIPv4MulticastTTL(fd *netFD, v int) error {
-       // TODO: Implement this
-       return syscall.EWINDOWS
+       fd.incref()
+       defer fd.decref()
+       err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_TTL, v)
+       if err != nil {
+               return os.NewSyscallError("setsockopt", err)
+       }
+       return nil
+
 }
 
 func ipv4MulticastLoopback(fd *netFD) (bool, error) {
@@ -36,8 +54,14 @@ func ipv4MulticastLoopback(fd *netFD) (bool, error) {
 }
 
 func setIPv4MulticastLoopback(fd *netFD, v bool) error {
-       // TODO: Implement this
-       return syscall.EWINDOWS
+       fd.incref()
+       defer fd.decref()
+       err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v))
+       if err != nil {
+               return os.NewSyscallError("setsockopt", err)
+       }
+       return nil
+
 }
 
 func ipv4ReceiveInterface(fd *netFD) (bool, error) {
index f2444a4d96f9c331242ca1c0fc898d46f951e4c9..128766144ddc3ba42151f6af29696971e9928bf4 100644 (file)
@@ -17,17 +17,17 @@ type TCPConn struct {
        plan9Conn
 }
 
-// SetDeadline implements the net.Conn SetDeadline method.
+// SetDeadline implements the Conn SetDeadline method.
 func (c *TCPConn) SetDeadline(t time.Time) error {
        return os.EPLAN9
 }
 
-// SetReadDeadline implements the net.Conn SetReadDeadline method.
+// SetReadDeadline implements the Conn SetReadDeadline method.
 func (c *TCPConn) SetReadDeadline(t time.Time) error {
        return os.EPLAN9
 }
 
-// SetWriteDeadline implements the net.Conn SetWriteDeadline method.
+// SetWriteDeadline implements the Conn SetWriteDeadline method.
 func (c *TCPConn) SetWriteDeadline(t time.Time) error {
        return os.EPLAN9
 }
index 65ec493039cbd9a360f99b38cf3f3179b268faf6..51a5d6f0ed8240fee42cee03e7557ffa898bb48f 100644 (file)
@@ -67,7 +67,7 @@ func (c *TCPConn) ok() bool { return c != nil && c.fd != nil }
 
 // Implementation of the Conn interface - see Conn for documentation.
 
-// Read implements the net.Conn Read method.
+// Read implements the Conn Read method.
 func (c *TCPConn) Read(b []byte) (n int, err error) {
        if !c.ok() {
                return 0, os.EINVAL
@@ -83,7 +83,7 @@ func (c *TCPConn) ReadFrom(r io.Reader) (int64, error) {
        return genericReadFrom(c, r)
 }
 
-// Write implements the net.Conn Write method.
+// Write implements the Conn Write method.
 func (c *TCPConn) Write(b []byte) (n int, err error) {
        if !c.ok() {
                return 0, os.EINVAL
@@ -135,7 +135,7 @@ func (c *TCPConn) RemoteAddr() Addr {
        return c.fd.raddr
 }
 
-// SetDeadline implements the net.Conn SetDeadline method.
+// SetDeadline implements the Conn SetDeadline method.
 func (c *TCPConn) SetDeadline(t time.Time) error {
        if !c.ok() {
                return os.EINVAL
@@ -143,7 +143,7 @@ func (c *TCPConn) SetDeadline(t time.Time) error {
        return setDeadline(c.fd, t)
 }
 
-// SetReadDeadline implements the net.Conn SetReadDeadline method.
+// SetReadDeadline implements the Conn SetReadDeadline method.
 func (c *TCPConn) SetReadDeadline(t time.Time) error {
        if !c.ok() {
                return os.EINVAL
@@ -151,7 +151,7 @@ func (c *TCPConn) SetReadDeadline(t time.Time) error {
        return setReadDeadline(c.fd, t)
 }
 
-// SetWriteDeadline implements the net.Conn SetWriteDeadline method.
+// SetWriteDeadline implements the Conn SetWriteDeadline method.
 func (c *TCPConn) SetWriteDeadline(t time.Time) error {
        if !c.ok() {
                return os.EINVAL
@@ -223,13 +223,13 @@ func (c *TCPConn) File() (f *os.File, err error) { return c.fd.dup() }
 // DialTCP connects to the remote address raddr on the network net,
 // which must be "tcp", "tcp4", or "tcp6".  If laddr is not nil, it is used
 // as the local address for the connection.
-func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err error) {
+func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
        if raddr == nil {
                return nil, &OpError{"dial", net, nil, errMissingAddress}
        }
-       fd, e := internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_STREAM, 0, "dial", sockaddrToTCP)
-       if e != nil {
-               return nil, e
+       fd, err := internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_STREAM, 0, "dial", sockaddrToTCP)
+       if err != nil {
+               return nil, err
        }
        return newTCPConn(fd), nil
 }
@@ -245,7 +245,7 @@ type TCPListener struct {
 // Net must be "tcp", "tcp4", or "tcp6".
 // If laddr has a port of 0, it means to listen on some available port.
 // The caller can use l.Addr() to retrieve the chosen address.
-func ListenTCP(net string, laddr *TCPAddr) (l *TCPListener, err error) {
+func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error) {
        fd, err := internetSocket(net, laddr.toAddr(), nil, syscall.SOCK_STREAM, 0, "listen", sockaddrToTCP)
        if err != nil {
                return nil, err
@@ -255,7 +255,7 @@ func ListenTCP(net string, laddr *TCPAddr) (l *TCPListener, err error) {
                closesocket(fd.sysfd)
                return nil, &OpError{"listen", net, laddr, err}
        }
-       l = new(TCPListener)
+       l := new(TCPListener)
        l.fd = fd
        return l, nil
 }
index 573438f85de3ca1c6f2c05d00749ce8f62df96d2..f90a5fe9ab853c24b4b94df09babb322a9b5d7db 100644 (file)
@@ -18,17 +18,17 @@ type UDPConn struct {
        plan9Conn
 }
 
-// SetDeadline implements the net.Conn SetDeadline method.
+// SetDeadline implements the Conn SetDeadline method.
 func (c *UDPConn) SetDeadline(t time.Time) error {
        return os.EPLAN9
 }
 
-// SetReadDeadline implements the net.Conn SetReadDeadline method.
+// SetReadDeadline implements the Conn SetReadDeadline method.
 func (c *UDPConn) SetReadDeadline(t time.Time) error {
        return os.EPLAN9
 }
 
-// SetWriteDeadline implements the net.Conn SetWriteDeadline method.
+// SetWriteDeadline implements the Conn SetWriteDeadline method.
 func (c *UDPConn) SetWriteDeadline(t time.Time) error {
        return os.EPLAN9
 }
@@ -66,7 +66,7 @@ func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
        return n, &UDPAddr{h.raddr, int(h.rport)}, nil
 }
 
-// ReadFrom implements the net.PacketConn ReadFrom method.
+// ReadFrom implements the PacketConn ReadFrom method.
 func (c *UDPConn) ReadFrom(b []byte) (n int, addr Addr, err error) {
        if !c.ok() {
                return 0, nil, os.EINVAL
@@ -103,7 +103,7 @@ func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (n int, err error) {
        return c.data.Write(buf)
 }
 
-// WriteTo implements the net.PacketConn WriteTo method.
+// WriteTo implements the PacketConn WriteTo method.
 func (c *UDPConn) WriteTo(b []byte, addr Addr) (n int, err error) {
        if !c.ok() {
                return 0, os.EINVAL
@@ -186,20 +186,10 @@ func ListenUDP(net string, laddr *UDPAddr) (c *UDPConn, err error) {
        return &UDPConn{*l.plan9Conn()}, nil
 }
 
-// JoinGroup joins the IP multicast group named by addr on ifi,
-// which specifies the interface to join.  JoinGroup uses the
-// default multicast interface if ifi is nil.
-func (c *UDPConn) JoinGroup(ifi *Interface, addr IP) error {
-       if !c.ok() {
-               return os.EINVAL
-       }
-       return os.EPLAN9
-}
-
-// LeaveGroup exits the IP multicast group named by addr on ifi.
-func (c *UDPConn) LeaveGroup(ifi *Interface, addr IP) error {
-       if !c.ok() {
-               return os.EINVAL
-       }
-       return os.EPLAN9
+// ListenMulticastUDP listens for incoming multicast UDP packets
+// addressed to the group address gaddr on ifi, which specifies
+// the interface to join.  ListenMulticastUDP uses default
+// multicast interface if ifi is nil.
+func ListenMulticastUDP(net string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
+       return nil, os.EPLAN9
 }
index fa3d29adfa8cf21826bf2f81288b25b14a6afafc..6108373568a9d2f0abd245223f2b97303a20f2bb 100644 (file)
@@ -60,16 +60,16 @@ func (c *UDPConn) ok() bool { return c != nil && c.fd != nil }
 
 // Implementation of the Conn interface - see Conn for documentation.
 
-// Read implements the net.Conn Read method.
-func (c *UDPConn) Read(b []byte) (n int, err error) {
+// Read implements the Conn Read method.
+func (c *UDPConn) Read(b []byte) (int, error) {
        if !c.ok() {
                return 0, os.EINVAL
        }
        return c.fd.Read(b)
 }
 
-// Write implements the net.Conn Write method.
-func (c *UDPConn) Write(b []byte) (n int, err error) {
+// Write implements the Conn Write method.
+func (c *UDPConn) Write(b []byte) (int, error) {
        if !c.ok() {
                return 0, os.EINVAL
        }
@@ -102,7 +102,7 @@ func (c *UDPConn) RemoteAddr() Addr {
        return c.fd.raddr
 }
 
-// SetDeadline implements the net.Conn SetDeadline method.
+// SetDeadline implements the Conn SetDeadline method.
 func (c *UDPConn) SetDeadline(t time.Time) error {
        if !c.ok() {
                return os.EINVAL
@@ -110,7 +110,7 @@ func (c *UDPConn) SetDeadline(t time.Time) error {
        return setDeadline(c.fd, t)
 }
 
-// SetReadDeadline implements the net.Conn SetReadDeadline method.
+// SetReadDeadline implements the Conn SetReadDeadline method.
 func (c *UDPConn) SetReadDeadline(t time.Time) error {
        if !c.ok() {
                return os.EINVAL
@@ -118,7 +118,7 @@ func (c *UDPConn) SetReadDeadline(t time.Time) error {
        return setReadDeadline(c.fd, t)
 }
 
-// SetWriteDeadline implements the net.Conn SetWriteDeadline method.
+// SetWriteDeadline implements the Conn SetWriteDeadline method.
 func (c *UDPConn) SetWriteDeadline(t time.Time) error {
        if !c.ok() {
                return os.EINVAL
@@ -166,8 +166,8 @@ func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
        return
 }
 
-// ReadFrom implements the net.PacketConn ReadFrom method.
-func (c *UDPConn) ReadFrom(b []byte) (n int, addr Addr, err error) {
+// ReadFrom implements the PacketConn ReadFrom method.
+func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) {
        if !c.ok() {
                return 0, nil, os.EINVAL
        }
@@ -195,7 +195,7 @@ func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) {
        return c.fd.WriteTo(b, sa)
 }
 
-// WriteTo implements the net.PacketConn WriteTo method.
+// WriteTo implements the PacketConn WriteTo method.
 func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error) {
        if !c.ok() {
                return 0, os.EINVAL
@@ -207,10 +207,15 @@ func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error) {
        return c.WriteToUDP(b, a)
 }
 
+// File returns a copy of the underlying os.File, set to blocking mode.
+// It is the caller's responsibility to close f when finished.
+// Closing c does not affect f, and closing f does not affect c.
+func (c *UDPConn) File() (f *os.File, err error) { return c.fd.dup() }
+
 // DialUDP connects to the remote address raddr on the network net,
 // which must be "udp", "udp4", or "udp6".  If laddr is not nil, it is used
 // as the local address for the connection.
-func DialUDP(net string, laddr, raddr *UDPAddr) (c *UDPConn, err error) {
+func DialUDP(net string, laddr, raddr *UDPAddr) (*UDPConn, error) {
        switch net {
        case "udp", "udp4", "udp6":
        default:
@@ -219,9 +224,9 @@ func DialUDP(net string, laddr, raddr *UDPAddr) (c *UDPConn, err error) {
        if raddr == nil {
                return nil, &OpError{"dial", net, nil, errMissingAddress}
        }
-       fd, e := internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_DGRAM, 0, "dial", sockaddrToUDP)
-       if e != nil {
-               return nil, e
+       fd, err := internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_DGRAM, 0, "dial", sockaddrToUDP)
+       if err != nil {
+               return nil, err
        }
        return newUDPConn(fd), nil
 }
@@ -246,36 +251,75 @@ func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
        return newUDPConn(fd), nil
 }
 
-// File returns a copy of the underlying os.File, set to blocking mode.
-// It is the caller's responsibility to close f when finished.
-// Closing c does not affect f, and closing f does not affect c.
-func (c *UDPConn) File() (f *os.File, err error) { return c.fd.dup() }
+// ListenMulticastUDP listens for incoming multicast UDP packets
+// addressed to the group address gaddr on ifi, which specifies
+// the interface to join.  ListenMulticastUDP uses default
+// multicast interface if ifi is nil.
+func ListenMulticastUDP(net string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
+       switch net {
+       case "udp", "udp4", "udp6":
+       default:
+               return nil, UnknownNetworkError(net)
+       }
+       if gaddr == nil || gaddr.IP == nil {
+               return nil, &OpError{"listenmulticastudp", "udp", nil, errMissingAddress}
+       }
+       fd, err := internetSocket(net, gaddr.toAddr(), nil, syscall.SOCK_DGRAM, 0, "listen", sockaddrToUDP)
+       if err != nil {
+               return nil, err
+       }
+       c := newUDPConn(fd)
+       ip4 := gaddr.IP.To4()
+       if ip4 != nil {
+               err := listenIPv4MulticastUDP(c, ifi, ip4)
+               if err != nil {
+                       c.Close()
+                       return nil, err
+               }
+       } else {
+               err := listenIPv6MulticastUDP(c, ifi, gaddr.IP)
+               if err != nil {
+                       c.Close()
+                       return nil, err
+               }
+       }
+       return c, nil
+}
 
-// JoinGroup joins the IP multicast group named by addr on ifi,
-// which specifies the interface to join.  JoinGroup uses the
-// default multicast interface if ifi is nil.
-func (c *UDPConn) JoinGroup(ifi *Interface, addr IP) error {
-       if !c.ok() {
-               return os.EINVAL
+func listenIPv4MulticastUDP(c *UDPConn, ifi *Interface, ip IP) error {
+       if ifi != nil {
+               err := setIPv4MulticastInterface(c.fd, ifi)
+               if err != nil {
+                       return err
+               }
+       }
+       err := setIPv4MulticastLoopback(c.fd, false)
+       if err != nil {
+               return err
        }
-       setDefaultMulticastSockopts(c.fd)
-       ip := addr.To4()
-       if ip != nil {
-               return joinIPv4GroupUDP(c, ifi, ip)
+       err = joinIPv4GroupUDP(c, ifi, ip)
+       if err != nil {
+               return err
        }
-       return joinIPv6GroupUDP(c, ifi, addr)
+       return nil
 }
 
-// LeaveGroup exits the IP multicast group named by addr on ifi.
-func (c *UDPConn) LeaveGroup(ifi *Interface, addr IP) error {
-       if !c.ok() {
-               return os.EINVAL
+func listenIPv6MulticastUDP(c *UDPConn, ifi *Interface, ip IP) error {
+       if ifi != nil {
+               err := setIPv6MulticastInterface(c.fd, ifi)
+               if err != nil {
+                       return err
+               }
        }
-       ip := addr.To4()
-       if ip != nil {
-               return leaveIPv4GroupUDP(c, ifi, ip)
+       err := setIPv6MulticastLoopback(c.fd, false)
+       if err != nil {
+               return err
+       }
+       err = joinIPv6GroupUDP(c, ifi, ip)
+       if err != nil {
+               return err
        }
-       return leaveIPv6GroupUDP(c, ifi, addr)
+       return nil
 }
 
 func joinIPv4GroupUDP(c *UDPConn, ifi *Interface, ip IP) error {
index e8087d09a360943b05f79f983995f325e766f115..1d9d7578f4fff0ff3692dd5164831775258f4562 100644 (file)
@@ -17,12 +17,12 @@ type UnixConn bool
 
 // Implementation of the Conn interface - see Conn for documentation.
 
-// Read implements the net.Conn Read method.
+// Read implements the Conn Read method.
 func (c *UnixConn) Read(b []byte) (n int, err error) {
        return 0, os.EPLAN9
 }
 
-// Write implements the net.Conn Write method.
+// Write implements the Conn Write method.
 func (c *UnixConn) Write(b []byte) (n int, err error) {
        return 0, os.EPLAN9
 }
@@ -45,28 +45,28 @@ func (c *UnixConn) RemoteAddr() Addr {
        return nil
 }
 
-// SetDeadline implements the net.Conn SetDeadline method.
+// SetDeadline implements the Conn SetDeadline method.
 func (c *UnixConn) SetDeadline(t time.Time) error {
        return os.EPLAN9
 }
 
-// SetReadDeadline implements the net.Conn SetReadDeadline method.
+// SetReadDeadline implements the Conn SetReadDeadline method.
 func (c *UnixConn) SetReadDeadline(t time.Time) error {
        return os.EPLAN9
 }
 
-// SetWriteDeadline implements the net.Conn SetWriteDeadline method.
+// SetWriteDeadline implements the Conn SetWriteDeadline method.
 func (c *UnixConn) SetWriteDeadline(t time.Time) error {
        return os.EPLAN9
 }
 
-// ReadFrom implements the net.PacketConn ReadFrom method.
+// ReadFrom implements the PacketConn ReadFrom method.
 func (c *UnixConn) ReadFrom(b []byte) (n int, addr Addr, err error) {
        err = os.EPLAN9
        return
 }
 
-// WriteTo implements the net.PacketConn WriteTo method.
+// WriteTo implements the PacketConn WriteTo method.
 func (c *UnixConn) WriteTo(b []byte, addr Addr) (n int, err error) {
        err = os.EPLAN9
        return
index e500ddb4e0f30a80ff1280315c58f9bf0b90a155..10b7966851155045b8ab988af7fcfd906f885f25 100644 (file)
@@ -120,7 +120,7 @@ func (c *UnixConn) ok() bool { return c != nil && c.fd != nil }
 
 // Implementation of the Conn interface - see Conn for documentation.
 
-// Read implements the net.Conn Read method.
+// Read implements the Conn Read method.
 func (c *UnixConn) Read(b []byte) (n int, err error) {
        if !c.ok() {
                return 0, os.EINVAL
@@ -128,7 +128,7 @@ func (c *UnixConn) Read(b []byte) (n int, err error) {
        return c.fd.Read(b)
 }
 
-// Write implements the net.Conn Write method.
+// Write implements the Conn Write method.
 func (c *UnixConn) Write(b []byte) (n int, err error) {
        if !c.ok() {
                return 0, os.EINVAL
@@ -165,7 +165,7 @@ func (c *UnixConn) RemoteAddr() Addr {
        return c.fd.raddr
 }
 
-// SetDeadline implements the net.Conn SetDeadline method.
+// SetDeadline implements the Conn SetDeadline method.
 func (c *UnixConn) SetDeadline(t time.Time) error {
        if !c.ok() {
                return os.EINVAL
@@ -173,7 +173,7 @@ func (c *UnixConn) SetDeadline(t time.Time) error {
        return setDeadline(c.fd, t)
 }
 
-// SetReadDeadline implements the net.Conn SetReadDeadline method.
+// SetReadDeadline implements the Conn SetReadDeadline method.
 func (c *UnixConn) SetReadDeadline(t time.Time) error {
        if !c.ok() {
                return os.EINVAL
@@ -181,7 +181,7 @@ func (c *UnixConn) SetReadDeadline(t time.Time) error {
        return setReadDeadline(c.fd, t)
 }
 
-// SetWriteDeadline implements the net.Conn SetWriteDeadline method.
+// SetWriteDeadline implements the Conn SetWriteDeadline method.
 func (c *UnixConn) SetWriteDeadline(t time.Time) error {
        if !c.ok() {
                return os.EINVAL
@@ -226,7 +226,7 @@ func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err error) {
        return
 }
 
-// ReadFrom implements the net.PacketConn ReadFrom method.
+// ReadFrom implements the PacketConn ReadFrom method.
 func (c *UnixConn) ReadFrom(b []byte) (n int, addr Addr, err error) {
        if !c.ok() {
                return 0, nil, os.EINVAL
@@ -252,7 +252,7 @@ func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (n int, err error) {
        return c.fd.WriteTo(b, sa)
 }
 
-// WriteTo implements the net.PacketConn WriteTo method.
+// WriteTo implements the PacketConn WriteTo method.
 func (c *UnixConn) WriteTo(b []byte, addr Addr) (n int, err error) {
        if !c.ok() {
                return 0, os.EINVAL
@@ -298,10 +298,10 @@ func (c *UnixConn) File() (f *os.File, err error) { return c.fd.dup() }
 // DialUnix connects to the remote address raddr on the network net,
 // which must be "unix" or "unixgram".  If laddr is not nil, it is used
 // as the local address for the connection.
-func DialUnix(net string, laddr, raddr *UnixAddr) (c *UnixConn, err error) {
-       fd, e := unixSocket(net, laddr, raddr, "dial")
-       if e != nil {
-               return nil, e
+func DialUnix(net string, laddr, raddr *UnixAddr) (*UnixConn, error) {
+       fd, err := unixSocket(net, laddr, raddr, "dial")
+       if err != nil {
+               return nil, err
        }
        return newUnixConn(fd), nil
 }
@@ -337,15 +337,15 @@ func ListenUnix(net string, laddr *UnixAddr) (*UnixListener, error) {
 
 // AcceptUnix accepts the next incoming call and returns the new connection
 // and the remote address.
-func (l *UnixListener) AcceptUnix() (c *UnixConn, err error) {
+func (l *UnixListener) AcceptUnix() (*UnixConn, error) {
        if l == nil || l.fd == nil {
                return nil, os.EINVAL
        }
-       fd, e := l.fd.accept(sockaddrToUnix)
-       if e != nil {
-               return nil, e
+       fd, err := l.fd.accept(sockaddrToUnix)
+       if err != nil {
+               return nil, err
        }
-       c = newUnixConn(fd)
+       c := newUnixConn(fd)
        return c, nil
 }
 
@@ -405,7 +405,7 @@ func (l *UnixListener) File() (f *os.File, err error) { return l.fd.dup() }
 // local address laddr.  The returned connection c's ReadFrom
 // and WriteTo methods can be used to receive and send UDP
 // packets with per-packet addressing.  The network net must be "unixgram".
-func ListenUnixgram(net string, laddr *UnixAddr) (c *UDPConn, err error) {
+func ListenUnixgram(net string, laddr *UnixAddr) (*UDPConn, error) {
        switch net {
        case "unixgram":
        default:
@@ -414,9 +414,9 @@ func ListenUnixgram(net string, laddr *UnixAddr) (c *UDPConn, err error) {
        if laddr == nil {
                return nil, &OpError{"listen", net, nil, errMissingAddress}
        }
-       fd, e := unixSocket(net, laddr, nil, "listen")
-       if e != nil {
-               return nil, e
+       fd, err := unixSocket(net, laddr, nil, "listen")
+       if err != nil {
+               return nil, err
        }
        return newUDPConn(fd), nil
 }
index 0068e98affa5fee73b615badc4d5cd147eefa156..a9ce3b31e24ecfb3c4c05e3653163d83cde0ba64 100644 (file)
@@ -431,30 +431,30 @@ func ParseWithReference(rawurlref string) (url *URL, err error) {
        return url, nil
 }
 
-// String reassembles url into a valid URL string.
-func (url *URL) String() string {
+// String reassembles the URL into a valid URL string.
+func (u *URL) String() string {
        // TODO: Rewrite to use bytes.Buffer
        result := ""
-       if url.Scheme != "" {
-               result += url.Scheme + ":"
+       if u.Scheme != "" {
+               result += u.Scheme + ":"
        }
-       if url.Opaque != "" {
-               result += url.Opaque
+       if u.Opaque != "" {
+               result += u.Opaque
        } else {
-               if url.Host != "" || url.User != nil {
+               if u.Host != "" || u.User != nil {
                        result += "//"
-                       if u := url.User; u != nil {
+                       if u := u.User; u != nil {
                                result += u.String() + "@"
                        }
-                       result += url.Host
+                       result += u.Host
                }
-               result += escape(url.Path, encodePath)
+               result += escape(u.Path, encodePath)
        }
-       if url.RawQuery != "" {
-               result += "?" + url.RawQuery
+       if u.RawQuery != "" {
+               result += "?" + u.RawQuery
        }
-       if url.Fragment != "" {
-               result += "#" + escape(url.Fragment, encodeFragment)
+       if u.Fragment != "" {
+               result += "#" + escape(u.Fragment, encodeFragment)
        }
        return result
 }
@@ -585,8 +585,8 @@ func resolvePath(basepath string, refpath string) string {
 }
 
 // IsAbs returns true if the URL is absolute.
-func (url *URL) IsAbs() bool {
-       return url.Scheme != ""
+func (u *URL) IsAbs() bool {
+       return u.Scheme != ""
 }
 
 // Parse parses a URL in the context of a base URL.  The URL in ref
index f42a61a1b13be5fdc51c111e8556a8d6c8d09719..854a548e5aafd7dc43ee752fb2be3b80116d1127 100644 (file)
@@ -795,8 +795,8 @@ func TestFormatters(t *testing.T) {
                                t.Errorf("For %q, expected error, got none.", c.in)
                                continue
                        }
-                       buf := bytes.NewBuffer(nil)
-                       err = tmpl.Execute(buf, data)
+                       var buf bytes.Buffer
+                       err = tmpl.Execute(&buf, data)
                        if err != nil {
                                t.Error("unexpected Execute error: ", err)
                                continue
index 33e223fd2963dcff621fcf8cc2365a33ff545153..6e0f168c76739513dd5b527fb802dada94e7b4ad 100644 (file)
@@ -12,11 +12,11 @@ import (
 // Process stores the information about a process created by StartProcess.
 type Process struct {
        Pid    int
-       handle int
+       handle uintptr
        done   bool // process has been successfuly waited on
 }
 
-func newProcess(pid, handle int) *Process {
+func newProcess(pid int, handle uintptr) *Process {
        p := &Process{Pid: pid, handle: handle}
        runtime.SetFinalizer(p, (*Process).Release)
        return p
index 11cfe79c724a41978bd0682e9c89e040532ea555..d00d12008f75030117144987d5ff01d67ac7e49f 100644 (file)
@@ -17,6 +17,7 @@ import (
        "runtime"
        "strconv"
        "strings"
+       "syscall"
        "testing"
 )
 
@@ -150,6 +151,15 @@ func TestExtraFiles(t *testing.T) {
                return
        }
 
+       // Ensure that file descriptors have not already been leaked into
+       // our environment.
+       for fd := os.Stderr.Fd() + 1; fd <= 101; fd++ {
+               err := syscall.Close(fd)
+               if err == nil {
+                       t.Logf("Something already leaked - closed fd %d", fd)
+               }
+       }
+
        // Force network usage, to verify the epoll (or whatever) fd
        // doesn't leak to the child,
        ln, err := net.Listen("tcp", "127.0.0.1:0")
@@ -202,6 +212,13 @@ func TestHelperProcess(*testing.T) {
        }
        defer os.Exit(0)
 
+       // Determine which command to use to display open files.
+       ofcmd := "lsof"
+       switch runtime.GOOS {
+       case "freebsd", "netbsd", "openbsd":
+               ofcmd = "fstat"
+       }
+
        args := os.Args
        for len(args) > 0 {
                if args[0] == "--" {
@@ -282,7 +299,7 @@ func TestHelperProcess(*testing.T) {
                                }
                                if got := f.Fd(); got != wantfd {
                                        fmt.Printf("leaked parent file. fd = %d; want %d\n", got, wantfd)
-                                       out, _ := Command("lsof", "-p", fmt.Sprint(os.Getpid())).CombinedOutput()
+                                       out, _ := Command(ofcmd, "-p", fmt.Sprint(os.Getpid())).CombinedOutput()
                                        fmt.Print(string(out))
                                        os.Exit(1)
                                }
@@ -292,6 +309,11 @@ func TestHelperProcess(*testing.T) {
                                f.Close()
                        }
                }
+               // Referring to fd3 here ensures that it is not
+               // garbage collected, and therefore closed, while
+               // executing the wantfd loop above.  It doesn't matter
+               // what we do with fd3 as long as we refer to it;
+               // closing it is the easy choice.
                fd3.Close()
                os.Stderr.Write(bs)
        case "exit":
index 218b8cdc1d68593602671e13e22c9c6e63c2f7fb..6465bfbb65376341dc41ee8d4ddbbae6bfff9b86 100644 (file)
@@ -48,7 +48,7 @@ func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err e
 
 // Kill causes the Process to exit immediately.
 func (p *Process) Kill() error {
-       return p.Signal(SIGKILL)
+       return p.Signal(UnixSignal(syscall.SIGKILL))
 }
 
 // Exec replaces the current process with an execution of the
index 7eb7d194d60edf0166a40447adb961c6ec2a7de7..9463d2c0e3ffd3bc7e8395a519c01fe7865b44a5 100644 (file)
@@ -29,7 +29,7 @@ func (p *Process) Wait(options int) (w *Waitmsg, err error) {
                return nil, NewSyscallError("GetExitCodeProcess", e)
        }
        p.done = true
-       return &Waitmsg{p.Pid, syscall.WaitStatus{s, ec}, new(syscall.Rusage)}, nil
+       return &Waitmsg{p.Pid, syscall.WaitStatus{Status: s, ExitCode: ec}, new(syscall.Rusage)}, nil
 }
 
 // Signal sends a signal to the Process.
@@ -37,8 +37,7 @@ func (p *Process) Signal(sig Signal) error {
        if p.done {
                return errors.New("os: process already finished")
        }
-       switch sig.(UnixSignal) {
-       case SIGKILL:
+       if us, ok := sig.(UnixSignal); ok && us == syscall.SIGKILL {
                e := syscall.TerminateProcess(syscall.Handle(p.handle), 1)
                return NewSyscallError("TerminateProcess", e)
        }
@@ -47,14 +46,14 @@ func (p *Process) Signal(sig Signal) error {
 
 // Release releases any resources associated with the Process.
 func (p *Process) Release() error {
-       if p.handle == -1 {
+       if p.handle == uintptr(syscall.InvalidHandle) {
                return EINVAL
        }
        e := syscall.CloseHandle(syscall.Handle(p.handle))
        if e != nil {
                return NewSyscallError("CloseHandle", e)
        }
-       p.handle = -1
+       p.handle = uintptr(syscall.InvalidHandle)
        // no need for a finalizer anymore
        runtime.SetFinalizer(p, nil)
        return nil
@@ -67,7 +66,7 @@ func findProcess(pid int) (p *Process, err error) {
        if e != nil {
                return nil, NewSyscallError("OpenProcess", e)
        }
-       return newProcess(pid, int(h)), nil
+       return newProcess(pid, uintptr(h)), nil
 }
 
 func init() {
index 9a9ed92ee3c1b48f3103ad114797c21134faa68b..8c61a82248f0cc8723d74976f22fea3a96b0ede2 100644 (file)
@@ -158,7 +158,7 @@ func (f *File) readdir(n int) (fi []FileInfo, err error) {
                if err == nil {
                        fi[i] = fip
                } else {
-                       fi[i] = &FileStat{name: filename}
+                       fi[i] = &fileStat{name: filename}
                }
        }
        return fi, err
index a0d3c99a503eeaab5d1f11ab5fcf57fc4ffd775b..56836434dbe3f94a7f92d8333897d77e98a87f1f 100644 (file)
@@ -30,7 +30,7 @@ func Getwd() (pwd string, err error) {
        pwd = Getenv("PWD")
        if len(pwd) > 0 && pwd[0] == '/' {
                d, err := Stat(pwd)
-               if err == nil && dot.(*FileStat).SameFile(d.(*FileStat)) {
+               if err == nil && SameFile(dot, d) {
                        return pwd, nil
                }
        }
@@ -42,7 +42,7 @@ func Getwd() (pwd string, err error) {
                // Can't stat root - no hope.
                return "", err
        }
-       if root.(*FileStat).SameFile(dot.(*FileStat)) {
+       if SameFile(root, dot) {
                return "/", nil
        }
 
@@ -67,7 +67,7 @@ func Getwd() (pwd string, err error) {
                        }
                        for _, name := range names {
                                d, _ := Lstat(parent + "/" + name)
-                               if d.(*FileStat).SameFile(dot.(*FileStat)) {
+                               if SameFile(d, dot) {
                                        pwd = "/" + name + pwd
                                        goto Found
                                }
@@ -82,7 +82,7 @@ func Getwd() (pwd string, err error) {
                        return "", err
                }
                fd.Close()
-               if pd.(*FileStat).SameFile(root.(*FileStat)) {
+               if SameFile(pd, root) {
                        break
                }
                // Set up for next round.
index 59f2bb061503f547d85f80704b128f69a8d388cd..36bb496d9791814b5135572eb4ab2d00595835ab 100644 (file)
@@ -406,7 +406,7 @@ func TestHardLink(t *testing.T) {
        if err != nil {
                t.Fatalf("stat %q failed: %v", from, err)
        }
-       if !tostat.(*FileStat).SameFile(fromstat.(*FileStat)) {
+       if !SameFile(tostat, fromstat) {
                t.Errorf("link %q, %q did not create hard link", to, from)
        }
 }
@@ -442,7 +442,7 @@ func TestSymLink(t *testing.T) {
        if err != nil {
                t.Fatalf("stat %q failed: %v", from, err)
        }
-       if !tostat.(*FileStat).SameFile(fromstat.(*FileStat)) {
+       if !SameFile(tostat, fromstat) {
                t.Errorf("symlink %q, %q did not create symlink", to, from)
        }
        fromstat, err = Lstat(from)
@@ -656,7 +656,7 @@ func TestChtimes(t *testing.T) {
        if err != nil {
                t.Fatalf("Stat %s: %s", f.Name(), err)
        }
-       preStat := st.(*FileStat)
+       preStat := st
 
        // Move access and modification time back a second
        at := Atime(preStat)
@@ -670,7 +670,7 @@ func TestChtimes(t *testing.T) {
        if err != nil {
                t.Fatalf("second Stat %s: %s", f.Name(), err)
        }
-       postStat := st.(*FileStat)
+       postStat := st
 
        /* Plan 9:
                Mtime is the time of the last change of content.  Similarly, atime is set whenever the
index 1bdcd748bc00991179f02e3beb2a7ec596af4b5e..f8e330beba468994b7c0d0cf374ff97b2096a477 100644 (file)
@@ -18,7 +18,7 @@ func checkUidGid(t *testing.T, path string, uid, gid int) {
        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)
+       sys := dir.Sys().(*syscall.Stat_t)
        if int(sys.Uid) != uid {
                t.Errorf("Stat %q: uid %d want %d", path, sys.Uid, uid)
        }
@@ -52,7 +52,7 @@ func TestChown(t *testing.T) {
        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)
+       sys := dir.Sys().(*syscall.Stat_t)
        checkUidGid(t, f.Name(), int(sys.Uid), gid)
 
        // Then try all the auxiliary groups.
index c664fc189b88cb2905952d81d113eeff64e426b6..789007206fa51f7bf1fe6729c9064be26379782f 100644 (file)
@@ -9,18 +9,18 @@ import (
        "time"
 )
 
-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 sameFile(sys1, sys2 interface{}) bool {
+       stat1 := sys1.(*syscall.Stat_t)
+       stat2 := sys2.(*syscall.Stat_t)
+       return stat1.Dev == stat2.Dev && stat1.Ino == stat2.Ino
 }
 
 func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
-       fs := &FileStat{
+       fs := &fileStat{
                name:    basename(name),
                size:    int64(st.Size),
                modTime: timespecToTime(st.Mtime),
-               Sys:     st,
+               sys:     st,
        }
        fs.mode = FileMode(st.Mode & 0777)
        switch st.Mode & syscall.S_IFMT {
@@ -52,5 +52,5 @@ func timespecToTime(ts syscall.Timespec) time.Time {
 
 // For testing.
 func atime(fi FileInfo) time.Time {
-       return timespecToTime(fi.(*FileStat).Sys.(*syscall.Stat_t).Atime)
+       return timespecToTime(fi.Sys().(*syscall.Stat_t).Atime)
 }
index 8d1323af9c6f14a13f0ec2a7dbe7cced23a9dab9..00506b2b6095dd6e35df7097eb0b451d1c5e8e20 100644 (file)
@@ -9,18 +9,18 @@ import (
        "time"
 )
 
-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 sameFile(sys1, sys2 interface{}) bool {
+       stat1 := sys1.(*syscall.Stat_t)
+       stat2 := sys2.(*syscall.Stat_t)
+       return stat1.Dev == stat2.Dev && stat1.Ino == stat2.Ino
 }
 
 func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
-       fs := &FileStat{
+       fs := &fileStat{
                name:    basename(name),
                size:    int64(st.Size),
                modTime: timespecToTime(st.Mtim),
-               Sys:     st,
+               sys:     st,
        }
        fs.mode = FileMode(st.Mode & 0777)
        switch st.Mode & syscall.S_IFMT {
@@ -57,5 +57,5 @@ func timespecToTime(ts syscall.Timespec) time.Time {
 
 // For testing.
 func atime(fi FileInfo) time.Time {
-       return timespecToTime(fi.(*FileStat).Sys.(*syscall.Stat_t).Atim)
+       return timespecToTime(fi.Sys().(*syscall.Stat_t).Atim)
 }
index f731e43740a8d268129e24439c2de2a7b626ed9c..7c2d1bd4efc421ea796c4f8d6ac8de09ede9649d 100644 (file)
@@ -9,18 +9,18 @@ import (
        "time"
 )
 
-func sameFile(fs1, fs2 *FileStat) bool {
-       a := fs1.Sys.(*Dir)
-       b := fs2.Sys.(*Dir)
+func sameFile(sys1, sys2 interface{}) bool {
+       a := sys1.(*Dir)
+       b := sys2.(*Dir)
        return a.Qid.Path == b.Qid.Path && a.Type == b.Type && a.Dev == b.Dev
 }
 
 func fileInfoFromStat(d *Dir) FileInfo {
-       fs := &FileStat{
+       fs := &fileStat{
                name:    d.Name,
                size:    int64(d.Length),
                modTime: time.Unix(int64(d.Mtime), 0),
-               Sys:     d,
+               sys:     d,
        }
        fs.mode = FileMode(d.Mode & 0777)
        if d.Mode&syscall.DMDIR != 0 {
@@ -100,5 +100,5 @@ func Lstat(name string) (FileInfo, error) {
 
 // For testing.
 func atime(fi FileInfo) time.Time {
-       return time.Unix(int64(fi.(*FileStat).Sys.(*Dir).Atime), 0)
+       return time.Unix(int64(fi.Sys().(*Dir).Atime), 0)
 }
index a3f187c25cb44f32d185efacdae34bbd29cc06d7..c7c5199be1c04365815e838e5a83335356d13074 100644 (file)
@@ -19,6 +19,7 @@ type FileInfo interface {
        Mode() FileMode     // file mode bits
        ModTime() time.Time // modification time
        IsDir() bool        // abbreviation for Mode().IsDir()
+       Sys() interface{}   // underlying data source (can return nil)
 }
 
 // A FileMode represents a file's mode and permission bits.
@@ -92,28 +93,33 @@ func (m FileMode) Perm() FileMode {
        return m & ModePerm
 }
 
-// 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 {
+// A fileStat is the implementation of FileInfo returned by Stat and Lstat.
+type fileStat struct {
        name    string
        size    int64
        mode    FileMode
        modTime time.Time
-
-       Sys interface{}
+       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() }
+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() }
+func (fs *fileStat) Sys() interface{}   { return fs.sys }
 
-// SameFile reports whether fs and other describe the same file.
+// SameFile reports whether fi1 and fi2 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)
+// SameFile only applies to results returned by this package's Stat.
+// It returns false in other cases.
+func SameFile(fi1, fi2 FileInfo) bool {
+       fs1, ok1 := fi1.(*fileStat)
+       fs2, ok2 := fi2.(*fileStat)
+       if !ok1 || !ok2 {
+               return false
+       }
+       return sameFile(fs1.sys, fs2.sys)
 }
index 10f5170a9c92666141340fcd50627373ee509871..415f869f2291b358a1592d20320093dc1e701862 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !cgo windows
+// +build !cgo,!windows
 
 package user
 
@@ -11,10 +11,18 @@ import (
        "runtime"
 )
 
+func init() {
+       implemented = false
+}
+
+func Current() (*User, error) {
+       return nil, fmt.Errorf("user: Current not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
+}
+
 func Lookup(username string) (*User, error) {
        return nil, fmt.Errorf("user: Lookup not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
 }
 
-func LookupId(int) (*User, error) {
+func LookupId(string) (*User, error) {
        return nil, fmt.Errorf("user: LookupId not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
 }
index 8939cebfcd82ca8f395c71c7cb6953d12cb5f679..68f8914d089c5911e11642023bf011727c4e9cd8 100644 (file)
@@ -9,6 +9,7 @@ package user
 
 import (
        "fmt"
+       "strconv"
        "strings"
        "syscall"
        "unsafe"
@@ -43,8 +44,9 @@ func bytePtrToString(p *byte) string {
        return string(a[:i])
 }
 
-func init() {
-       implemented = true
+// Current returns the current user. 
+func Current() (*User, error) {
+       return lookup(syscall.Getuid(), "", false)
 }
 
 // Lookup looks up a user by username. If the user cannot be found,
@@ -55,8 +57,12 @@ func Lookup(username string) (*User, error) {
 
 // LookupId looks up a user by userid. If the user cannot be found,
 // the returned error is of type UnknownUserIdError.
-func LookupId(uid int) (*User, error) {
-       return lookup(uid, "", false)
+func LookupId(uid string) (*User, error) {
+       i, e := strconv.Atoi(uid)
+       if e != nil {
+               return nil, e
+       }
+       return lookup(i, "", false)
 }
 
 func lookup(uid int, username string, lookupByName bool) (*User, error) {
@@ -92,8 +98,8 @@ func lookup(uid int, username string, lookupByName bool) (*User, error) {
                }
        }
        u := &User{
-               Uid:      int(pwd.Pw_uid),
-               Gid:      int(pwd.Pw_gid),
+               Uid:      strconv.Itoa(int(pwd.Pw_uid)),
+               Gid:      strconv.Itoa(int(pwd.Pw_gid)),
                Username: bytePtrToString((*byte)(unsafe.Pointer(pwd.Pw_name))),
                Name:     bytePtrToString((*byte)(unsafe.Pointer(pwd.Pw_gecos))),
                HomeDir:  bytePtrToString((*byte)(unsafe.Pointer(pwd.Pw_dir))),
diff --git a/libgo/go/os/user/lookup_windows.go b/libgo/go/os/user/lookup_windows.go
new file mode 100644 (file)
index 0000000..9936871
--- /dev/null
@@ -0,0 +1,117 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package user
+
+import (
+       "fmt"
+       "syscall"
+       "unsafe"
+)
+
+func lookupFullName(domain, username, domainAndUser string) (string, error) {
+       // try domain controller first
+       name, e := syscall.TranslateAccountName(domainAndUser,
+               syscall.NameSamCompatible, syscall.NameDisplay, 50)
+       if e != nil {
+               // domain lookup failed, perhaps this pc is not part of domain
+               d := syscall.StringToUTF16Ptr(domain)
+               u := syscall.StringToUTF16Ptr(username)
+               var p *byte
+               e := syscall.NetUserGetInfo(d, u, 10, &p)
+               if e != nil {
+                       return "", e
+               }
+               defer syscall.NetApiBufferFree(p)
+               i := (*syscall.UserInfo10)(unsafe.Pointer(p))
+               if i.FullName == nil {
+                       return "", nil
+               }
+               name = syscall.UTF16ToString((*[1024]uint16)(unsafe.Pointer(i.FullName))[:])
+       }
+       return name, nil
+}
+
+func newUser(usid *syscall.SID, gid, dir string) (*User, error) {
+       username, domain, t, e := usid.LookupAccount("")
+       if e != nil {
+               return nil, e
+       }
+       if t != syscall.SidTypeUser {
+               return nil, fmt.Errorf("user: should be user account type, not %d", t)
+       }
+       domainAndUser := domain + `\` + username
+       uid, e := usid.String()
+       if e != nil {
+               return nil, e
+       }
+       name, e := lookupFullName(domain, username, domainAndUser)
+       if e != nil {
+               return nil, e
+       }
+       u := &User{
+               Uid:      uid,
+               Gid:      gid,
+               Username: domainAndUser,
+               Name:     name,
+               HomeDir:  dir,
+       }
+       return u, nil
+}
+
+// Current returns the current user.
+func Current() (*User, error) {
+       t, e := syscall.OpenCurrentProcessToken()
+       if e != nil {
+               return nil, e
+       }
+       u, e := t.GetTokenUser()
+       if e != nil {
+               return nil, e
+       }
+       pg, e := t.GetTokenPrimaryGroup()
+       if e != nil {
+               return nil, e
+       }
+       gid, e := pg.PrimaryGroup.String()
+       if e != nil {
+               return nil, e
+       }
+       dir, e := t.GetUserProfileDirectory()
+       if e != nil {
+               return nil, e
+       }
+       return newUser(u.User.Sid, gid, dir)
+}
+
+// BUG(brainman): Lookup and LookupId functions do not set
+// Gid and HomeDir fields in the User struct returned on windows.
+
+func newUserFromSid(usid *syscall.SID) (*User, error) {
+       // TODO(brainman): do not know where to get gid and dir fields
+       gid := "unknown"
+       dir := "Unknown directory"
+       return newUser(usid, gid, dir)
+}
+
+// Lookup looks up a user by username.
+func Lookup(username string) (*User, error) {
+       sid, _, t, e := syscall.LookupSID("", username)
+       if e != nil {
+               return nil, e
+       }
+       if t != syscall.SidTypeUser {
+               return nil, fmt.Errorf("user: should be user account type, not %d", t)
+       }
+       return newUserFromSid(sid)
+}
+
+// LookupId looks up a user by userid.
+func LookupId(uid string) (*User, error) {
+       sid, e := syscall.StringToSid(uid)
+       if e != nil {
+               return nil, e
+       }
+       return newUserFromSid(sid)
+}
index a0195377765e5da561c165dffe4fb4be8941f345..841f2263f95f9819fef4c172c98a2d7cbfc63538 100644 (file)
@@ -9,12 +9,16 @@ import (
        "strconv"
 )
 
-var implemented = false // set to true by lookup_unix.go's init
+var implemented = true // set to false by lookup_stubs.go's init
 
 // User represents a user account.
+//
+// On posix systems Uid and Gid contain a decimal number
+// representing uid and gid. On windows Uid and Gid
+// contain security identifier (SID) in a string format.
 type User struct {
-       Uid      int // user id
-       Gid      int // primary group id
+       Uid      string // user id
+       Gid      string // primary group id
        Username string
        Name     string
        HomeDir  string
index f9f44af8a93a9007c657b434e38310cf1dd1eb3b..b812ebce79a100fcc3e05b08120b9577b3aec4de 100644 (file)
@@ -6,9 +6,7 @@ package user
 
 import (
        "os"
-       "reflect"
        "runtime"
-       "syscall"
        "testing"
 )
 
@@ -18,7 +16,8 @@ func skip(t *testing.T) bool {
                return true
        }
 
-       if runtime.GOOS == "linux" || runtime.GOOS == "freebsd" || runtime.GOOS == "darwin" {
+       switch runtime.GOOS {
+       case "linux", "freebsd", "darwin", "windows":
                return false
        }
 
@@ -26,36 +25,75 @@ func skip(t *testing.T) bool {
        return true
 }
 
-func TestLookup(t *testing.T) {
+func TestCurrent(t *testing.T) {
        if skip(t) {
                return
        }
 
-       // Test LookupId on the current user
-       uid := syscall.Getuid()
-       u, err := LookupId(uid)
+       u, err := Current()
        if err != nil {
-               t.Fatalf("LookupId: %v", err)
-       }
-       if e, g := uid, u.Uid; e != g {
-               t.Errorf("expected Uid of %d; got %d", e, g)
+               t.Fatalf("Current: %v", err)
        }
        fi, err := os.Stat(u.HomeDir)
        if err != nil || !fi.IsDir() {
-               t.Errorf("expected a valid HomeDir; stat(%q): err=%v, IsDir=%v", u.HomeDir, err, fi.IsDir())
+               t.Errorf("expected a valid HomeDir; stat(%q): err=%v", u.HomeDir, err)
        }
        if u.Username == "" {
                t.Fatalf("didn't get a username")
        }
+}
+
+func compare(t *testing.T, want, got *User) {
+       if want.Uid != got.Uid {
+               t.Errorf("got Uid=%q; want %q", got.Uid, want.Uid)
+       }
+       if want.Username != got.Username {
+               t.Errorf("got Username=%q; want %q", got.Username, want.Username)
+       }
+       if want.Name != got.Name {
+               t.Errorf("got Name=%q; want %q", got.Name, want.Name)
+       }
+       // TODO(brainman): fix it once we know how.
+       if runtime.GOOS == "windows" {
+               t.Log("skipping Gid and HomeDir comparisons")
+               return
+       }
+       if want.Gid != got.Gid {
+               t.Errorf("got Gid=%q; want %q", got.Gid, want.Gid)
+       }
+       if want.HomeDir != got.HomeDir {
+               t.Errorf("got HomeDir=%q; want %q", got.HomeDir, want.HomeDir)
+       }
+}
+
+func TestLookup(t *testing.T) {
+       if skip(t) {
+               return
+       }
 
-       // Test Lookup by username, using the username from LookupId
-       un, err := Lookup(u.Username)
+       want, err := Current()
+       if err != nil {
+               t.Fatalf("Current: %v", err)
+       }
+       got, err := Lookup(want.Username)
        if err != nil {
                t.Fatalf("Lookup: %v", err)
        }
-       if !reflect.DeepEqual(u, un) {
-               t.Errorf("Lookup by userid vs. name didn't match\n"+
-                       "LookupId(%d): %#v\n"+
-                       "Lookup(%q): %#v\n", uid, u, u.Username, un)
+       compare(t, want, got)
+}
+
+func TestLookupId(t *testing.T) {
+       if skip(t) {
+               return
+       }
+
+       want, err := Current()
+       if err != nil {
+               t.Fatalf("Current: %v", err)
+       }
+       got, err := LookupId(want.Uid)
+       if err != nil {
+               t.Fatalf("LookupId: %v", err)
        }
+       compare(t, want, got)
 }
index 2601d1838487fd2a4c80c6c6c7ac3c193cf9286a..fdcc637759c082f2816f9fed8d856c547d1c9b88 100644 (file)
@@ -5,6 +5,7 @@
 package filepath_test
 
 import (
+       "io/ioutil"
        "os"
        "path/filepath"
        "reflect"
@@ -547,6 +548,7 @@ func TestIsAbs(t *testing.T) {
 }
 
 type EvalSymlinksTest struct {
+       // If dest is empty, the path is created; otherwise the dest is symlinked to the path.
        path, dest string
 }
 
@@ -574,31 +576,42 @@ var EvalSymlinksAbsWindowsTests = []EvalSymlinksTest{
        {`c:\`, `c:\`},
 }
 
-func testEvalSymlinks(t *testing.T, tests []EvalSymlinksTest) {
-       for _, d := range tests {
-               if p, err := filepath.EvalSymlinks(d.path); err != nil {
-                       t.Errorf("EvalSymlinks(%q) error: %v", d.path, err)
-               } else if filepath.Clean(p) != filepath.Clean(d.dest) {
-                       t.Errorf("EvalSymlinks(%q)=%q, want %q", d.path, p, d.dest)
-               }
-       }
+// simpleJoin builds a file name from the directory and path.
+// It does not use Join because we don't want ".." to be evaluated.
+func simpleJoin(dir, path string) string {
+       return dir + string(filepath.Separator) + path
 }
 
 func TestEvalSymlinks(t *testing.T) {
-       defer os.RemoveAll("test")
+       tmpDir, err := ioutil.TempDir("", "evalsymlink")
+       if err != nil {
+               t.Fatal("creating temp dir:", err)
+       }
+       defer os.RemoveAll(tmpDir)
+
+       // /tmp may itself be a symlink! Avoid the confusion, although
+       // it means trusting the thing we're testing.
+       tmpDir, err = filepath.EvalSymlinks(tmpDir)
+       if err != nil {
+               t.Fatal("eval symlink for tmp dir:", err)
+       }
+
+       // Create the symlink farm using relative paths.
        for _, d := range EvalSymlinksTestDirs {
                var err error
+               path := simpleJoin(tmpDir, d.path)
                if d.dest == "" {
-                       err = os.Mkdir(d.path, 0755)
+                       err = os.Mkdir(path, 0755)
                } else {
                        if runtime.GOOS != "windows" {
-                               err = os.Symlink(d.dest, d.path)
+                               err = os.Symlink(d.dest, path)
                        }
                }
                if err != nil {
                        t.Fatal(err)
                }
        }
+
        var tests []EvalSymlinksTest
        if runtime.GOOS == "windows" {
                for _, d := range EvalSymlinksTests {
@@ -610,26 +623,17 @@ func TestEvalSymlinks(t *testing.T) {
        } else {
                tests = EvalSymlinksTests
        }
-       // relative
-       testEvalSymlinks(t, tests)
-       // absolute
-       /* 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)
-       }
-       testroot := filepath.Join(goroot, "src", "pkg", "path", "filepath")
-       for i, d := range tests {
-               tests[i].path = filepath.Join(testroot, d.path)
-               tests[i].dest = filepath.Join(testroot, d.dest)
-       }
-       if runtime.GOOS == "windows" {
-               for _, d := range EvalSymlinksAbsWindowsTests {
-                       tests = append(tests, d)
+
+       // Evaluate the symlink farm.
+       for _, d := range tests {
+               path := simpleJoin(tmpDir, d.path)
+               dest := simpleJoin(tmpDir, d.dest)
+               if p, err := filepath.EvalSymlinks(path); err != nil {
+                       t.Errorf("EvalSymlinks(%q) error: %v", d.path, err)
+               } else if filepath.Clean(p) != filepath.Clean(dest) {
+                       t.Errorf("Clean(%q)=%q, want %q", path, p, dest)
                }
        }
-       testEvalSymlinks(t, tests)
-       */
 }
 
 /* These tests do not work in the gccgo test environment.
@@ -638,16 +642,19 @@ func TestEvalSymlinks(t *testing.T) {
 var abstests = []string{
        "../AUTHORS",
        "pkg/../../AUTHORS",
-       "Make.pkg",
-       "pkg/Makefile",
+       "Make.inc",
+       "pkg/math",
        ".",
-       "$GOROOT/src/Make.pkg",
-       "$GOROOT/src/../src/Make.pkg",
+       "$GOROOT/src/Make.inc",
+       "$GOROOT/src/../src/Make.inc",
        "$GOROOT/misc/cgo",
        "$GOROOT",
 }
 
 func TestAbs(t *testing.T) {
+       t.Logf("test needs to be rewritten; disabled")
+       return
+
        oldwd, err := os.Getwd()
        if err != nil {
                t.Fatal("Getwd failed: " + err.Error())
@@ -670,7 +677,7 @@ func TestAbs(t *testing.T) {
                        continue
                }
                absinfo, err := os.Stat(abspath)
-               if err != nil || !absinfo.(*os.FileStat).SameFile(info.(*os.FileStat)) {
+               if err != nil || !os.SameFile(absinfo, info) {
                        t.Errorf("Abs(%q)=%q, not the same file", path, abspath)
                }
                if !filepath.IsAbs(abspath) {
index 11dfb3fe516d89fc90b7e96276f01186705a0b2b..557fb8e843eb4ca4515e50168ba29f6ae6b1f872 100644 (file)
@@ -1547,15 +1547,19 @@ func TestAddr(t *testing.T) {
 func noAlloc(t *testing.T, n int, f func(int)) {
        // once to prime everything
        f(-1)
-       runtime.MemStats.Mallocs = 0
+       memstats := new(runtime.MemStats)
+       runtime.ReadMemStats(memstats)
+       oldmallocs := memstats.Mallocs
 
        for j := 0; j < n; j++ {
                f(j)
        }
        // A few allocs may happen in the testing package when GOMAXPROCS > 1, so don't
        // require zero mallocs.
-       if runtime.MemStats.Mallocs > 5 {
-               t.Fatalf("%d mallocs after %d iterations", runtime.MemStats.Mallocs, n)
+       runtime.ReadMemStats(memstats)
+       mallocs := memstats.Mallocs - oldmallocs
+       if mallocs > 5 {
+               t.Fatalf("%d mallocs after %d iterations", mallocs, n)
        }
 }
 
index 02855df0f390905226e88f52b28591c5ca9bdadf..1bb0a26b7a6bfcab7d99f1de4c25cd53a7136699 100644 (file)
@@ -789,6 +789,14 @@ func (t *structType) Field(i int) (f StructField) {
                f.Tag = StructTag(*p.tag)
        }
        f.Offset = p.offset
+
+       // NOTE(rsc): This is the only allocation in the interface
+       // presented by a reflect.Type.  It would be nice to avoid,
+       // at least in the common cases, but we need to make sure
+       // that misbehaving clients of reflect cannot affect other
+       // uses of reflect.  One possibility is CL 5371098, but we
+       // postponed that ugliness until there is a demonstrated
+       // need for the performance.  This is issue 2320.
        f.Index = []int{i}
        return
 }
index ba641c1e6fd1100998bff98b04432ae67056118d..07688bef9c4b0864b507a330febba30e569490ab 100644 (file)
@@ -1377,8 +1377,8 @@ func (p *parser) appendGroup(r []rune, g charGroup) []rune {
 }
 
 var anyTable = &unicode.RangeTable{
-       []unicode.Range16{{0, 1<<16 - 1, 1}},
-       []unicode.Range32{{1 << 16, unicode.MaxRune, 1}},
+       R16: []unicode.Range16{{Lo: 0, Hi: 1<<16 - 1, Stride: 1}},
+       R32: []unicode.Range32{{Lo: 1 << 16, Hi: unicode.MaxRune, Stride: 1}},
 }
 
 // unicodeTable returns the unicode.RangeTable identified by name
index 00b3a04ce9d0f0fcd82af1f1db9ea6509d8007b7..739ebcba2ff81e1580959ac784471869734b3fdf 100644 (file)
@@ -10,20 +10,21 @@ import (
 )
 
 func TestGcSys(t *testing.T) {
+       memstats := new(runtime.MemStats)
        runtime.GC()
-       runtime.UpdateMemStats()
-       sys := runtime.MemStats.Sys
+       runtime.ReadMemStats(memstats)
+       sys := memstats.Sys
 
        for i := 0; i < 1000000; i++ {
                workthegc()
        }
 
        // Should only be using a few MB.
-       runtime.UpdateMemStats()
-       if sys > runtime.MemStats.Sys {
+       runtime.ReadMemStats(memstats)
+       if sys > memstats.Sys {
                sys = 0
        } else {
-               sys = runtime.MemStats.Sys - sys
+               sys = memstats.Sys - sys
        }
        t.Logf("used %d extra bytes", sys)
        if sys > 4<<20 {
index 3f2130629105eae80618388ca27a10a3b32845d4..1301674c027adc923d2a377510ec0a2b808a82b5 100644 (file)
@@ -6,9 +6,9 @@ package runtime
 
 import "unsafe"
 
-type MemStatsType struct {
+// A MemStats records statistics about the memory allocator.
+type MemStats struct {
        // General statistics.
-       // Not locked during update; approximate.
        Alloc      uint64 // bytes allocated and still in use
        TotalAlloc uint64 // bytes allocated (even if freed)
        Sys        uint64 // bytes obtained from system (should be sum of XxxSys below)
@@ -43,7 +43,6 @@ type MemStatsType struct {
        DebugGC      bool
 
        // Per-size allocation statistics.
-       // Not locked during update; approximate.
        // 61 is NumSizeClasses in the C code.
        BySize [61]struct {
                Size    uint32
@@ -54,21 +53,17 @@ type MemStatsType struct {
 
 var Sizeof_C_MStats uintptr // filled in by malloc.goc
 
+var VmemStats MemStats
+
 func init() {
-       if Sizeof_C_MStats != unsafe.Sizeof(MemStats) {
-               println(Sizeof_C_MStats, unsafe.Sizeof(MemStats))
+       if Sizeof_C_MStats != unsafe.Sizeof(VmemStats) {
+               println(Sizeof_C_MStats, unsafe.Sizeof(VmemStats))
                panic("MStats vs MemStatsType size mismatch")
        }
 }
 
-// MemStats holds statistics about the memory system.
-// The statistics may be out of date, as the information is
-// updated lazily from per-thread caches.
-// Use UpdateMemStats to bring the statistics up to date.
-var MemStats MemStatsType
-
-// UpdateMemStats brings MemStats up to date.
-func UpdateMemStats()
+// ReadMemStats populates m with memory allocator statistics.
+func ReadMemStats(m *MemStats)
 
 // GC runs a garbage collection.
 func GC()
index d14bb141c4a8b4ae602eb4288de8b391abf7b3b5..a8e78e0ea754ad81ff933ad166178ff2a1a4b62b 100644 (file)
@@ -75,7 +75,8 @@ func WriteHeapProfile(w io.Writer) error {
 
        // Print memstats information too.
        // Pprof will ignore, but useful for people.
-       s := &runtime.MemStats
+       s := new(runtime.MemStats)
+       runtime.ReadMemStats(s)
        fmt.Fprintf(b, "\n# runtime.MemStats\n")
        fmt.Fprintf(b, "# Alloc = %d\n", s.Alloc)
        fmt.Fprintf(b, "# TotalAlloc = %d\n", s.TotalAlloc)
index 186f16c27db2ec123e0d999ac0852202fd96bed3..bac23e6ea6742c816ca9f10367f82e22c193e72c 100644 (file)
@@ -127,11 +127,12 @@ func TestUitoa(t *testing.T) {
 }
 
 func numAllocations(f func()) int {
-       runtime.UpdateMemStats()
-       n0 := runtime.MemStats.Mallocs
+       memstats := new(runtime.MemStats)
+       runtime.ReadMemStats(memstats)
+       n0 := memstats.Mallocs
        f()
-       runtime.UpdateMemStats()
-       return int(runtime.MemStats.Mallocs - n0)
+       runtime.ReadMemStats(memstats)
+       return int(memstats.Mallocs - n0)
 }
 
 /* This test relies on escape analysis which gccgo does not yet do.
diff --git a/libgo/go/strings/example_test.go b/libgo/go/strings/example_test.go
new file mode 100644 (file)
index 0000000..16e5367
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strings_test
+
+import (
+       "fmt"
+       "strings"
+)
+
+// Fields are: ["foo" "bar" "baz"]
+func ExampleFields() {
+       fmt.Printf("Fields are: %q", strings.Fields("  foo bar  baz   "))
+}
index 518573318efa59908192d70fae4b9f85972c3be0..2848d9b32b87864e03e879d704fb958e2dd7dfb6 100644 (file)
 
 package syscall
 
-import "errors"
+import (
+       "errors"
+       "sync"
+)
 
-func Getenv(key string) (value string, found bool) {
-       if len(key) == 0 {
-               return "", false
+var (
+       // envOnce guards initialization by copyenv, which populates env.
+       envOnce sync.Once
+
+       // envLock guards env.
+       envLock sync.RWMutex
+
+       // env maps from an environment variable to its value.
+       env map[string]string
+)
+
+func readenv(key string) (string, error) {
+       fd, err := Open("/env/"+key, O_RDONLY)
+       if err != nil {
+               return "", err
        }
-       f, e := Open("/env/"+key, O_RDONLY)
-       if e != nil {
-               return "", false
+       defer Close(fd)
+       l, _ := Seek(fd, 0, 2)
+       Seek(fd, 0, 0)
+       buf := make([]byte, l)
+       n, err := Read(fd, buf)
+       if err != nil {
+               return "", err
        }
-       defer Close(f)
+       if n > 0 && buf[n-1] == 0 {
+               buf = buf[:n-1]
+       }
+       return string(buf), nil
+}
 
-       l, _ := Seek(f, 0, 2)
-       Seek(f, 0, 0)
-       buf := make([]byte, l)
-       n, e := Read(f, buf)
-       if e != nil {
+func writeenv(key, value string) error {
+       fd, err := Create("/env/"+key, O_RDWR, 0666)
+       if err != nil {
+               return err
+       }
+       defer Close(fd)
+       _, err = Write(fd, []byte(value))
+       return err
+}
+
+func copyenv() {
+       env = make(map[string]string)
+       fd, err := Open("/env", O_RDONLY)
+       if err != nil {
+               return
+       }
+       defer Close(fd)
+       files, err := readdirnames(fd)
+       if err != nil {
+               return
+       }
+       for _, key := range files {
+               v, err := readenv(key)
+               if err != nil {
+                       continue
+               }
+               env[key] = v
+       }
+}
+
+func Getenv(key string) (value string, found bool) {
+       envOnce.Do(copyenv)
+       if len(key) == 0 {
                return "", false
        }
 
-       if n > 0 && buf[n-1] == 0 {
-               buf = buf[:n-1]
+       envLock.RLock()
+       defer envLock.RUnlock()
+
+       v, ok := env[key]
+       if !ok {
+               return "", false
        }
-       return string(buf), true
+       return v, true
 }
 
 func Setenv(key, value string) error {
+       envOnce.Do(copyenv)
        if len(key) == 0 {
-               return errors.New("bad arg in system call")
+               return errors.New("zero length key")
        }
 
-       f, e := Create("/env/"+key, O_RDWR, 0666)
-       if e != nil {
-               return e
-       }
-       defer Close(f)
+       envLock.Lock()
+       defer envLock.Unlock()
 
-       _, e = Write(f, []byte(value))
+       err := writeenv(key, value)
+       if err != nil {
+               return err
+       }
+       env[key] = value
        return nil
 }
 
 func Clearenv() {
+       envOnce.Do(copyenv) // prevent copyenv in Getenv/Setenv
+
+       envLock.Lock()
+       defer envLock.Unlock()
+
+       env = make(map[string]string)
        RawSyscall(SYS_RFORK, RFCENVG, 0, 0)
 }
 
 func Environ() []string {
-       env := make([]string, 0, 100)
-
-       f, e := Open("/env", O_RDONLY)
-       if e != nil {
-               panic(e)
-       }
-       defer Close(f)
-
-       names, e := readdirnames(f)
-       if e != nil {
-               panic(e)
-       }
-
-       for _, k := range names {
-               if v, ok := Getenv(k); ok {
-                       env = append(env, k+"="+v)
-               }
+       envOnce.Do(copyenv)
+       envLock.RLock()
+       defer envLock.RUnlock()
+       a := make([]string, len(env))
+       i := 0
+       for k, v := range env {
+               a[i] = k + "=" + v
+               i++
        }
-       return env[0:len(env)]
+       return a
 }
index 131ebaae87c03e9ba158fa717173da2bd1dfe4cb..75f0f45adaff6a25143f87784147e41e16b61f6f 100644 (file)
@@ -244,7 +244,7 @@ func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error)
 }
 
 // StartProcess wraps ForkExec for package os.
-func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid, handle int, err error) {
+func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) {
        pid, err = forkExec(argv0, argv, attr)
        return pid, 0, err
 }
index 2826e2f35a6ccdc0f1c3e7ae0475f8274a476da5..6cb25a7d00a9362bbfca5641eebe89bfca3b1042 100644 (file)
@@ -232,7 +232,7 @@ type SysProcAttr struct {
 var zeroProcAttr ProcAttr
 var zeroSysProcAttr SysProcAttr
 
-func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid, handle int, err error) {
+func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) {
        if len(argv0) == 0 {
                return 0, 0, EWINDOWS
        }
@@ -319,7 +319,7 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid, handle int,
        }
        defer CloseHandle(Handle(pi.Thread))
 
-       return int(pi.ProcessId), int(pi.Process), nil
+       return int(pi.ProcessId), uintptr(pi.Process), nil
 }
 
 func Exec(argv0 string, argv []string, envv []string) (err error) {
diff --git a/libgo/go/syscall/security_windows.go b/libgo/go/syscall/security_windows.go
new file mode 100644 (file)
index 0000000..bd40fe5
--- /dev/null
@@ -0,0 +1,359 @@
+// Copyright 2012 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+import (
+       "unsafe"
+)
+
+const (
+       STANDARD_RIGHTS_REQUIRED = 0xf0000
+       STANDARD_RIGHTS_READ     = 0x20000
+       STANDARD_RIGHTS_WRITE    = 0x20000
+       STANDARD_RIGHTS_EXECUTE  = 0x20000
+       STANDARD_RIGHTS_ALL      = 0x1F0000
+)
+
+const (
+       NameUnknown          = 0
+       NameFullyQualifiedDN = 1
+       NameSamCompatible    = 2
+       NameDisplay          = 3
+       NameUniqueId         = 6
+       NameCanonical        = 7
+       NameUserPrincipal    = 8
+       NameCanonicalEx      = 9
+       NameServicePrincipal = 10
+       NameDnsDomain        = 12
+)
+
+// This function returns 1 byte BOOLEAN rather than the 4 byte BOOL.
+// http://blogs.msdn.com/b/drnick/archive/2007/12/19/windows-and-upn-format-credentials.aspx
+//sys  TranslateName(accName *uint16, accNameFormat uint32, desiredNameFormat uint32, translatedName *uint16, nSize *uint32) (err error) [failretval&0xff==0] = secur32.TranslateNameW
+//sys  GetUserNameEx(nameFormat uint32, nameBuffre *uint16, nSize *uint32) (err error) [failretval&0xff==0] = secur32.GetUserNameExW
+
+// TranslateAccountName converts a directory service
+// object name from one format to another.
+func TranslateAccountName(username string, from, to uint32, initSize int) (string, error) {
+       u := StringToUTF16Ptr(username)
+       b := make([]uint16, 50)
+       n := uint32(len(b))
+       e := TranslateName(u, from, to, &b[0], &n)
+       if e != nil {
+               if e != ERROR_INSUFFICIENT_BUFFER {
+                       return "", e
+               }
+               // make receive buffers of requested size and try again
+               b = make([]uint16, n)
+               e = TranslateName(u, from, to, &b[0], &n)
+               if e != nil {
+                       return "", e
+               }
+       }
+       return UTF16ToString(b), nil
+}
+
+type UserInfo10 struct {
+       Name       *uint16
+       Comment    *uint16
+       UsrComment *uint16
+       FullName   *uint16
+}
+
+//sys  NetUserGetInfo(serverName *uint16, userName *uint16, level uint32, buf **byte) (neterr error) = netapi32.NetUserGetInfo
+//sys  NetApiBufferFree(buf *byte) (neterr error) = netapi32.NetApiBufferFree
+
+const (
+       // do not reorder
+       SidTypeUser = 1 << iota
+       SidTypeGroup
+       SidTypeDomain
+       SidTypeAlias
+       SidTypeWellKnownGroup
+       SidTypeDeletedAccount
+       SidTypeInvalid
+       SidTypeUnknown
+       SidTypeComputer
+       SidTypeLabel
+)
+
+//sys  LookupAccountSid(systemName *uint16, sid *SID, name *uint16, nameLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) = advapi32.LookupAccountSidW
+//sys  LookupAccountName(systemName *uint16, accountName *uint16, sid *SID, sidLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) = advapi32.LookupAccountNameW
+//sys  ConvertSidToStringSid(sid *SID, stringSid **uint16) (err error) = advapi32.ConvertSidToStringSidW
+//sys  ConvertStringSidToSid(stringSid *uint16, sid **SID) (err error) = advapi32.ConvertStringSidToSidW
+//sys  GetLengthSid(sid *SID) (len uint32) = advapi32.GetLengthSid
+//sys  CopySid(destSidLen uint32, destSid *SID, srcSid *SID) (err error) = advapi32.CopySid
+
+// The security identifier (SID) structure is a variable-length
+// structure used to uniquely identify users or groups.
+type SID struct{}
+
+// StringToSid converts a string-format security identifier
+// sid into a valid, functional sid.
+func StringToSid(s string) (*SID, error) {
+       var sid *SID
+       e := ConvertStringSidToSid(StringToUTF16Ptr(s), &sid)
+       if e != nil {
+               return nil, e
+       }
+       defer LocalFree((Handle)(unsafe.Pointer(sid)))
+       return sid.Copy()
+}
+
+// LookupSID retrieves a security identifier sid for the account
+// and the name of the domain on which the account was found.
+// System specify target computer to search.
+func LookupSID(system, account string) (sid *SID, domain string, accType uint32, err error) {
+       if len(account) == 0 {
+               return nil, "", 0, EINVAL
+       }
+       acc := StringToUTF16Ptr(account)
+       var sys *uint16
+       if len(system) > 0 {
+               sys = StringToUTF16Ptr(system)
+       }
+       db := make([]uint16, 50)
+       dn := uint32(len(db))
+       b := make([]byte, 50)
+       n := uint32(len(b))
+       sid = (*SID)(unsafe.Pointer(&b[0]))
+       e := LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType)
+       if e != nil {
+               if e != ERROR_INSUFFICIENT_BUFFER {
+                       return nil, "", 0, e
+               }
+               // make receive buffers of requested size and try again
+               b = make([]byte, n)
+               sid = (*SID)(unsafe.Pointer(&b[0]))
+               db = make([]uint16, dn)
+               e = LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType)
+               if e != nil {
+                       return nil, "", 0, e
+               }
+       }
+       return sid, UTF16ToString(db), accType, nil
+}
+
+// String converts sid to a string format
+// suitable for display, storage, or transmission.
+func (sid *SID) String() (string, error) {
+       var s *uint16
+       e := ConvertSidToStringSid(sid, &s)
+       if e != nil {
+               return "", e
+       }
+       defer LocalFree((Handle)(unsafe.Pointer(s)))
+       return UTF16ToString((*[256]uint16)(unsafe.Pointer(s))[:]), nil
+}
+
+// Len returns the length, in bytes, of a valid security identifier sid.
+func (sid *SID) Len() int {
+       return int(GetLengthSid(sid))
+}
+
+// Copy creates a duplicate of security identifier sid.
+func (sid *SID) Copy() (*SID, error) {
+       b := make([]byte, sid.Len())
+       sid2 := (*SID)(unsafe.Pointer(&b[0]))
+       e := CopySid(uint32(len(b)), sid2, sid)
+       if e != nil {
+               return nil, e
+       }
+       return sid2, nil
+}
+
+// LookupAccount retrieves the name of the account for this sid
+// and the name of the first domain on which this sid is found.
+// System specify target computer to search for.
+func (sid *SID) LookupAccount(system string) (account, domain string, accType uint32, err error) {
+       var sys *uint16
+       if len(system) > 0 {
+               sys = StringToUTF16Ptr(system)
+       }
+       b := make([]uint16, 50)
+       n := uint32(len(b))
+       db := make([]uint16, 50)
+       dn := uint32(len(db))
+       e := LookupAccountSid(sys, sid, &b[0], &n, &db[0], &dn, &accType)
+       if e != nil {
+               if e != ERROR_INSUFFICIENT_BUFFER {
+                       return "", "", 0, e
+               }
+               // make receive buffers of requested size and try again
+               b = make([]uint16, n)
+               db = make([]uint16, dn)
+               e = LookupAccountSid(nil, sid, &b[0], &n, &db[0], &dn, &accType)
+               if e != nil {
+                       return "", "", 0, e
+               }
+       }
+       return UTF16ToString(b), UTF16ToString(db), accType, nil
+}
+
+const (
+       // do not reorder
+       TOKEN_ASSIGN_PRIMARY = 1 << iota
+       TOKEN_DUPLICATE
+       TOKEN_IMPERSONATE
+       TOKEN_QUERY
+       TOKEN_QUERY_SOURCE
+       TOKEN_ADJUST_PRIVILEGES
+       TOKEN_ADJUST_GROUPS
+       TOKEN_ADJUST_DEFAULT
+
+       TOKEN_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED |
+               TOKEN_ASSIGN_PRIMARY |
+               TOKEN_DUPLICATE |
+               TOKEN_IMPERSONATE |
+               TOKEN_QUERY |
+               TOKEN_QUERY_SOURCE |
+               TOKEN_ADJUST_PRIVILEGES |
+               TOKEN_ADJUST_GROUPS |
+               TOKEN_ADJUST_DEFAULT
+       TOKEN_READ  = STANDARD_RIGHTS_READ | TOKEN_QUERY
+       TOKEN_WRITE = STANDARD_RIGHTS_WRITE |
+               TOKEN_ADJUST_PRIVILEGES |
+               TOKEN_ADJUST_GROUPS |
+               TOKEN_ADJUST_DEFAULT
+       TOKEN_EXECUTE = STANDARD_RIGHTS_EXECUTE
+)
+
+const (
+       // do not reorder
+       TokenUser = 1 + iota
+       TokenGroups
+       TokenPrivileges
+       TokenOwner
+       TokenPrimaryGroup
+       TokenDefaultDacl
+       TokenSource
+       TokenType
+       TokenImpersonationLevel
+       TokenStatistics
+       TokenRestrictedSids
+       TokenSessionId
+       TokenGroupsAndPrivileges
+       TokenSessionReference
+       TokenSandBoxInert
+       TokenAuditPolicy
+       TokenOrigin
+       TokenElevationType
+       TokenLinkedToken
+       TokenElevation
+       TokenHasRestrictions
+       TokenAccessInformation
+       TokenVirtualizationAllowed
+       TokenVirtualizationEnabled
+       TokenIntegrityLevel
+       TokenUIAccess
+       TokenMandatoryPolicy
+       TokenLogonSid
+       MaxTokenInfoClass
+)
+
+type SIDAndAttributes struct {
+       Sid        *SID
+       Attributes uint32
+}
+
+type Tokenuser struct {
+       User SIDAndAttributes
+}
+
+type Tokenprimarygroup struct {
+       PrimaryGroup *SID
+}
+
+//sys  OpenProcessToken(h Handle, access uint32, token *Token) (err error) = advapi32.OpenProcessToken
+//sys  GetTokenInformation(t Token, infoClass uint32, info *byte, infoLen uint32, returnedLen *uint32) (err error) = advapi32.GetTokenInformation
+//sys  GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) = userenv.GetUserProfileDirectoryW
+
+// An access token contains the security information for a logon session.
+// The system creates an access token when a user logs on, and every
+// process executed on behalf of the user has a copy of the token.
+// The token identifies the user, the user's groups, and the user's
+// privileges. The system uses the token to control access to securable
+// objects and to control the ability of the user to perform various
+// system-related operations on the local computer.
+type Token Handle
+
+// OpenCurrentProcessToken opens the access token
+// associated with current process.
+func OpenCurrentProcessToken() (Token, error) {
+       p, e := GetCurrentProcess()
+       if e != nil {
+               return 0, e
+       }
+       var t Token
+       e = OpenProcessToken(p, TOKEN_QUERY, &t)
+       if e != nil {
+               return 0, e
+       }
+       return t, nil
+}
+
+// Close releases access to access token.
+func (t Token) Close() error {
+       return CloseHandle(Handle(t))
+}
+
+// getInfo retrieves a specified type of information about an access token.
+func (t Token) getInfo(class uint32, initSize int) (unsafe.Pointer, error) {
+       b := make([]byte, initSize)
+       var n uint32
+       e := GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
+       if e != nil {
+               if e != ERROR_INSUFFICIENT_BUFFER {
+                       return nil, e
+               }
+               // make receive buffers of requested size and try again
+               b = make([]byte, n)
+               e = GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
+               if e != nil {
+                       return nil, e
+               }
+       }
+       return unsafe.Pointer(&b[0]), nil
+}
+
+// GetTokenUser retrieves access token t user account information.
+func (t Token) GetTokenUser() (*Tokenuser, error) {
+       i, e := t.getInfo(TokenUser, 50)
+       if e != nil {
+               return nil, e
+       }
+       return (*Tokenuser)(i), nil
+}
+
+// GetTokenPrimaryGroup retrieves access token t primary group information.
+// A pointer to a SID structure representing a group that will become
+// the primary group of any objects created by a process using this access token.
+func (t Token) GetTokenPrimaryGroup() (*Tokenprimarygroup, error) {
+       i, e := t.getInfo(TokenPrimaryGroup, 50)
+       if e != nil {
+               return nil, e
+       }
+       return (*Tokenprimarygroup)(i), nil
+}
+
+// GetUserProfileDirectory retrieves path to the
+// root directory of the access token t user's profile.
+func (t Token) GetUserProfileDirectory() (string, error) {
+       b := make([]uint16, 100)
+       n := uint32(len(b))
+       e := GetUserProfileDirectory(t, &b[0], &n)
+       if e != nil {
+               if e != ERROR_INSUFFICIENT_BUFFER {
+                       return "", e
+               }
+               // make receive buffers of requested size and try again
+               b = make([]uint16, n)
+               e = GetUserProfileDirectory(t, &b[0], &n)
+               if e != nil {
+                       return "", e
+               }
+       }
+       return UTF16ToString(b), nil
+}
index f77719789928224302fa80d748bb11c327a95d27..4efaaec3bd28ed3a4d6b8b586d2d58d8ff94a8a7 100644 (file)
@@ -33,6 +33,7 @@ func StringBytePtr(s string) *byte { return &StringByteSlice(s)[0] }
 var _zero uintptr
 
 var dummy *byte
+
 const sizeofPtr uintptr = uintptr(unsafe.Sizeof(dummy))
 
 func (ts *Timespec) Unix() (sec int64, nsec int64) {
@@ -42,3 +43,11 @@ func (ts *Timespec) Unix() (sec int64, nsec int64) {
 func (tv *Timeval) Unix() (sec int64, nsec int64) {
        return int64(tv.Sec), int64(tv.Usec) * 1000
 }
+
+func (ts *Timespec) Nano() int64 {
+       return int64(ts.Sec)*1e9 + int64(ts.Nsec)
+}
+
+func (tv *Timeval) Nano() int64 {
+       return int64(tv.Sec)*1e9 + int64(tv.Usec)*1000
+}
index f1acb97e1b64cccb4db2fac7a1cbe2090d09c70c..68ecebb36f44ba2365699a10756b90b22bbbbcbd 100644 (file)
@@ -225,6 +225,19 @@ func (c *common) Fatalf(format string, args ...interface{}) {
        c.FailNow()
 }
 
+// TODO(dsymonds): Consider hooking into runtime·traceback instead.
+func (c *common) stack() {
+       for i := 2; ; i++ { // Caller we care about is the user, 2 frames up
+               pc, file, line, ok := runtime.Caller(i)
+               f := runtime.FuncForPC(pc)
+               if !ok || f == nil {
+                       break
+               }
+               c.Logf("%s:%d (0x%x)", file, line, pc)
+               c.Logf("\t%s", f.Name())
+       }
+}
+
 // Parallel signals that this test is to be run in parallel with (and only with) 
 // other parallel tests in this CPU group.
 func (t *T) Parallel() {
@@ -247,6 +260,13 @@ func tRunner(t *T, test *InternalTest) {
        // a call to runtime.Goexit, record the duration and send
        // a signal saying that the test is done.
        defer func() {
+               // Consider any uncaught panic a failure.
+               if err := recover(); err != nil {
+                       t.failed = true
+                       t.Log(err)
+                       t.stack()
+               }
+
                t.duration = time.Now().Sub(t.start)
                t.signal <- t
        }()
index 201a685c6305656b8319e19bae17eb7e1072d66b..ea7c40081115b3f58be753d00e1d8b7624f2e31a 100644 (file)
@@ -52,7 +52,7 @@ type cell struct {
 // this flag.
 //
 // If a Writer is configured to filter HTML, HTML tags and entities
-// are simply passed through. The widths of tags and entities are
+// are passed through. The widths of tags and entities are
 // assumed to be zero (tags) and one (entities) for formatting purposes.
 //
 // A segment of text may be escaped by bracketing it with Escape
@@ -448,7 +448,7 @@ func handlePanic(err *error) {
 
 // Flush should be called after the last call to Write to ensure
 // that any data buffered in the Writer is written to output. Any
-// incomplete escape sequence at the end is simply considered
+// incomplete escape sequence at the end is considered
 // complete for formatting purposes.
 //
 func (b *Writer) Flush() (err error) {
index 86336b1b908fcc1db67b89bc8a42628311a7a232..29bf167e56b62039930cf275e4e807cda7da20da 100644 (file)
@@ -9,7 +9,7 @@
 
 package unicode
 
-var TurkishCase = _TurkishCase
+var TurkishCase SpecialCase = _TurkishCase
 var _TurkishCase = SpecialCase{
        CaseRange{0x0049, 0x0049, d{0, 0x131 - 0x49, 0}},
        CaseRange{0x0069, 0x0069, d{0x130 - 0x69, 0, 0x130 - 0x69}},
@@ -17,4 +17,4 @@ var _TurkishCase = SpecialCase{
        CaseRange{0x0131, 0x0131, d{0x49 - 0x131, 0, 0x49 - 0x131}},
 }
 
-var AzeriCase = _TurkishCase
+var AzeriCase SpecialCase = _TurkishCase
index a3b882625ef5affae0f3de4dccf9a32904261f15..978c48ae43ee9115e6932208cdbe895bf1a8da26 100644 (file)
@@ -2701,6 +2701,7 @@ var _Zs = &RangeTable{
        },
 }
 
+// The following variables are of type *RangeTable:
 var (
        Cc     = _Cc // Cc is the set of Unicode characters in category Cc.
        Cf     = _Cf // Cf is the set of Unicode characters in category Cf.
@@ -4053,6 +4054,7 @@ var _Yi = &RangeTable{
        },
 }
 
+// The following variables are of type *RangeTable:
 var (
        Arabic                 = _Arabic                 // Arabic is the set of Unicode characters in script Arabic.
        Armenian               = _Armenian               // Armenian is the set of Unicode characters in script Armenian.
@@ -5114,6 +5116,7 @@ var _White_Space = &RangeTable{
        },
 }
 
+// The following variables are of type *RangeTable:
 var (
        ASCII_Hex_Digit                    = _ASCII_Hex_Digit                    // ASCII_Hex_Digit is the set of Unicode characters with property ASCII_Hex_Digit.
        Bidi_Control                       = _Bidi_Control                       // Bidi_Control is the set of Unicode characters with property Bidi_Control.
index aa7d9ff3ae256ac2c00d76e1ee6a7f9fc5ed980b..c1cf02c6debf973b65546d3d951af305547df144 100644 (file)
@@ -235,7 +235,7 @@ struct MStats
 };
 
 extern MStats mstats
-  __asm__ ("libgo_runtime.runtime.MemStats");
+  __asm__ ("libgo_runtime.runtime.VmemStats");
 
 
 // Size classes.  Computed and initialized by InitSizes.
index 26633ab1f1879224d04d198cc3395c5f87073a0b..bd634d533e9461680358a5f6b92ceef86b558c82 100644 (file)
@@ -1061,11 +1061,11 @@ runtime_gc(int32 force)
                runtime_gc(1);
 }
 
-void runtime_UpdateMemStats(void)
-  __asm__("libgo_runtime.runtime.UpdateMemStats");
+void runtime_ReadMemStats(MStats *)
+  __asm__("libgo_runtime.runtime.ReadMemStats");
 
 void
-runtime_UpdateMemStats(void)
+runtime_ReadMemStats(MStats *stats)
 {
        M *m;
 
@@ -1078,6 +1078,7 @@ runtime_UpdateMemStats(void)
        m->gcing = 1;
        runtime_stoptheworld();
        cachestats();
+       *stats = mstats;
        m->gcing = 0;
        runtime_semrelease(&gcsema);
        runtime_starttheworld(false);
index 04412bd67e2b6fc925af13fe2fb7400af8b924c3..42a5779bc992c1f564338a49a1002bb9371a5934 100644 (file)
@@ -525,7 +525,7 @@ mcommoninit(M *m)
        runtime_atomicstorep((void**)&runtime_allm, m);
 
        m->id = runtime_sched.mcount++;
-       m->fastrand = 0x49f6428aUL + m->id;
+       m->fastrand = 0x49f6428aUL + m->id + runtime_cputicks();
 
        if(m->mcache == nil)
                m->mcache = runtime_allocmcache();
index 922fa20448d2acc20b9f0fdccb0d80e032479df1..7c8c436deebeae19fcb9124f4ea81320acb4efa1 100644 (file)
@@ -184,6 +184,19 @@ runtime_fastrand1(void)
        return x;
 }
 
+int64
+runtime_cputicks(void)
+{
+#if defined(__386__) || defined(__x86_64__)
+  uint32 low, high;
+  asm("rdtsc" : "=a" (low), "=d" (high));
+  return (int64)(((uint64)high << 32) | (uint64)low);
+#else
+  // FIXME: implement for other processors.
+  return 0;
+#endif
+}
+
 struct funcline_go_return
 {
   String retfile;
index 253c49b21f376773392e42868c798c7970477dc6..41b0ef5f00734c5abe5536a7a9a18b810a83f086 100644 (file)
@@ -286,6 +286,7 @@ void        runtime_exitsyscall(void) __asm__("libgo_syscall.syscall.exitsyscall");
 void   siginit(void);
 bool   __go_sigsend(int32 sig);
 int64  runtime_nanotime(void);
+int64  runtime_cputicks(void);
 
 void   runtime_stoptheworld(void);
 void   runtime_starttheworld(bool);