summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2011-06-28 15:28:34 +0200
committerOndřej Surý <ondrej@sury.org>2011-06-28 15:28:34 +0200
commit8d00b02d82d86abe51773dc2c1751843bb538ae5 (patch)
tree6656d166a046fc751548e88f071fedbeb9355443 /src
parentc29cace1e8f3260389ea78fa4ef86d80cd5e5275 (diff)
downloadgolang-8d00b02d82d86abe51773dc2c1751843bb538ae5.tar.gz
Imported Upstream version 2011.06.23upstream-weekly/2011.06.23
Diffstat (limited to 'src')
-rw-r--r--src/Make.ccmd3
-rw-r--r--src/Make.clib1
-rwxr-xr-xsrc/all-qemu.bash3
-rw-r--r--src/cmd/5c/txt.c28
-rw-r--r--src/cmd/5g/ggen.c32
-rw-r--r--src/cmd/5g/gobj.c4
-rw-r--r--src/cmd/5g/gsubr.c71
-rw-r--r--src/cmd/5g/reg.c43
-rw-r--r--src/cmd/5l/noop.c24
-rw-r--r--src/cmd/6c/cgen.c2
-rw-r--r--src/cmd/6g/ggen.c32
-rw-r--r--src/cmd/6g/gobj.c4
-rw-r--r--src/cmd/6g/gsubr.c51
-rw-r--r--src/cmd/6g/reg.c1
-rw-r--r--src/cmd/8a/l.s734
-rw-r--r--src/cmd/8c/cgen.c2
-rw-r--r--src/cmd/8g/ggen.c32
-rw-r--r--src/cmd/8g/gobj.c4
-rw-r--r--src/cmd/8g/gsubr.c51
-rw-r--r--src/cmd/8g/reg.c1
-rw-r--r--src/cmd/8l/asm.c6
-rw-r--r--src/cmd/8l/list.c2
-rw-r--r--src/cmd/8l/obj.c17
-rw-r--r--src/cmd/8l/pass.c1
-rw-r--r--src/cmd/8l/span.c4
-rw-r--r--src/cmd/cc/dcl.c1
-rw-r--r--src/cmd/cgo/gcc.go95
-rw-r--r--src/cmd/cgo/main.go3
-rw-r--r--src/cmd/cgo/out.go17
-rw-r--r--src/cmd/cgo/util.go2
-rw-r--r--src/cmd/cov/Makefile3
-rw-r--r--src/cmd/gc/builtin.c.boot10
-rw-r--r--src/cmd/gc/dcl.c25
-rw-r--r--src/cmd/gc/gen.c213
-rw-r--r--src/cmd/gc/go.h26
-rw-r--r--src/cmd/gc/go.y47
-rw-r--r--src/cmd/gc/lex.c18
-rw-r--r--src/cmd/gc/pgen.c32
-rw-r--r--src/cmd/gc/runtime.go1
-rw-r--r--src/cmd/gc/subr.c30
-rw-r--r--src/cmd/gc/typecheck.c7
-rw-r--r--src/cmd/gc/unsafe.c2
-rw-r--r--src/cmd/gc/unsafe.go8
-rw-r--r--src/cmd/gc/walk.c11
-rw-r--r--src/cmd/godefs/Makefile3
-rwxr-xr-xsrc/cmd/godefs/test.sh45
-rw-r--r--src/cmd/godefs/testdata.c41
-rw-r--r--src/cmd/godefs/testdata_darwin_386.golden31
-rw-r--r--src/cmd/godefs/testdata_darwin_amd64.golden31
-rw-r--r--src/cmd/godoc/Makefile2
-rw-r--r--src/cmd/godoc/codewalk.go30
-rw-r--r--src/cmd/godoc/dirtrees.go37
-rw-r--r--src/cmd/godoc/filesystem.go96
-rw-r--r--src/cmd/godoc/godoc.go47
-rw-r--r--src/cmd/godoc/index.go11
-rw-r--r--src/cmd/godoc/main.go4
-rw-r--r--src/cmd/godoc/mapping.go3
-rw-r--r--src/cmd/godoc/parser.go69
-rw-r--r--src/cmd/godoc/utils.go7
-rw-r--r--src/cmd/gofix/Makefile2
-rw-r--r--src/cmd/gofix/httpfinalurl.go2
-rw-r--r--src/cmd/gofix/httpheaders.go66
-rw-r--r--src/cmd/gofix/httpheaders_test.go73
-rw-r--r--src/cmd/gofix/main.go2
-rw-r--r--src/cmd/gofix/oserrorstring.go75
-rw-r--r--src/cmd/gofix/oserrorstring_test.go57
-rw-r--r--src/cmd/gofix/osopen.go2
-rw-r--r--src/cmd/gofix/testdata/reflect.decoder.go.out6
-rw-r--r--src/cmd/gofix/testdata/reflect.encoder.go.out2
-rw-r--r--src/cmd/gofix/testdata/reflect.export.go.out12
-rw-r--r--src/cmd/gofix/testdata/reflect.print.go.out2
-rw-r--r--src/cmd/gofix/testdata/reflect.read.go.out4
-rw-r--r--src/cmd/gofix/testdata/reflect.scan.go.out8
-rw-r--r--src/cmd/gofix/testdata/reflect.type.go.out4
-rw-r--r--src/cmd/goinstall/Makefile17
-rw-r--r--src/cmd/goinstall/doc.go12
-rw-r--r--src/cmd/goinstall/download.go144
-rw-r--r--src/cmd/goinstall/main.go88
-rw-r--r--src/cmd/goinstall/make.go60
-rw-r--r--src/cmd/goinstall/parse.go172
-rw-r--r--src/cmd/goinstall/path.go149
-rw-r--r--src/cmd/goinstall/syslist_test.go61
-rw-r--r--src/cmd/gopack/Makefile3
-rw-r--r--src/cmd/gotype/gotype.go2
-rw-r--r--src/cmd/hgpatch/main.go14
-rw-r--r--src/cmd/ld/data.c28
-rw-r--r--src/cmd/ld/dwarf.c27
-rw-r--r--src/cmd/ld/elf.h74
-rw-r--r--src/cmd/ld/ldelf.c7
-rw-r--r--src/cmd/ld/ldmacho.c1
-rw-r--r--src/cmd/ld/ldpe.c12
-rw-r--r--src/cmd/ld/lib.h2
-rw-r--r--src/cmd/ld/pe.c6
-rw-r--r--src/cmd/ld/symtab.c11
-rw-r--r--src/cmd/nm/Makefile3
-rw-r--r--src/cmd/prof/Makefile3
-rwxr-xr-xsrc/cmd/prof/gopprof287
-rw-r--r--src/env.bash45
-rw-r--r--src/libmach/8db.c54
-rw-r--r--src/libmach/linux.c23
-rw-r--r--src/pkg/Makefile33
-rw-r--r--src/pkg/archive/tar/reader.go2
-rwxr-xr-xsrc/pkg/big/int.go6
-rwxr-xr-xsrc/pkg/big/nat.go4
-rw-r--r--src/pkg/big/rat.go10
-rw-r--r--src/pkg/bufio/bufio.go4
-rw-r--r--src/pkg/bytes/buffer.go4
-rw-r--r--src/pkg/compress/gzip/gunzip.go4
-rw-r--r--src/pkg/compress/zlib/reader.go6
-rw-r--r--src/pkg/crypto/cast5/cast5.go2
-rw-r--r--src/pkg/crypto/dsa/dsa.go4
-rw-r--r--src/pkg/crypto/openpgp/elgamal/Makefile11
-rw-r--r--src/pkg/crypto/openpgp/elgamal/elgamal.go122
-rw-r--r--src/pkg/crypto/openpgp/elgamal/elgamal_test.go49
-rw-r--r--src/pkg/crypto/openpgp/keys.go78
-rw-r--r--src/pkg/crypto/openpgp/packet/encrypted_key.go132
-rw-r--r--src/pkg/crypto/openpgp/packet/encrypted_key_test.go86
-rw-r--r--src/pkg/crypto/openpgp/packet/one_pass_signature.go27
-rw-r--r--src/pkg/crypto/openpgp/packet/packet.go26
-rw-r--r--src/pkg/crypto/openpgp/packet/private_key.go24
-rw-r--r--src/pkg/crypto/openpgp/packet/private_key_test.go64
-rw-r--r--src/pkg/crypto/openpgp/packet/public_key.go43
-rw-r--r--src/pkg/crypto/openpgp/packet/signature.go12
-rw-r--r--src/pkg/crypto/openpgp/packet/symmetric_key_encrypted.go6
-rw-r--r--src/pkg/crypto/openpgp/packet/symmetrically_encrypted.go4
-rw-r--r--src/pkg/crypto/openpgp/packet/symmetrically_encrypted_test.go2
-rw-r--r--src/pkg/crypto/openpgp/read.go9
-rw-r--r--src/pkg/crypto/openpgp/read_test.go96
-rw-r--r--src/pkg/crypto/openpgp/write.go193
-rw-r--r--src/pkg/crypto/openpgp/write_test.go111
-rw-r--r--src/pkg/crypto/rsa/pkcs1v15.go4
-rw-r--r--src/pkg/crypto/rsa/rsa.go10
-rw-r--r--src/pkg/crypto/tls/conn.go4
-rw-r--r--src/pkg/crypto/tls/handshake_client.go6
-rw-r--r--src/pkg/crypto/tls/handshake_server.go6
-rw-r--r--src/pkg/crypto/tls/key_agreement.go33
-rw-r--r--src/pkg/crypto/tls/tls.go8
-rw-r--r--src/pkg/crypto/x509/verify_test.go2
-rw-r--r--src/pkg/crypto/x509/x509.go14
-rw-r--r--src/pkg/debug/dwarf/type.go15
-rw-r--r--src/pkg/debug/elf/file.go30
-rw-r--r--src/pkg/debug/elf/file_test.go6
-rw-r--r--src/pkg/debug/elf/testdata/go-relocation-test-gcc424-x86-64.obj (renamed from src/pkg/debug/elf/testdata/go-relocation-test-gcc424-x86-64.o)bin3088 -> 3088 bytes
-rw-r--r--src/pkg/debug/elf/testdata/go-relocation-test-gcc441-x86-64.obj (renamed from src/pkg/debug/elf/testdata/go-relocation-test-gcc441-x86-64.o)bin2936 -> 2936 bytes
-rw-r--r--src/pkg/debug/elf/testdata/go-relocation-test-gcc441-x86.obj (renamed from src/pkg/debug/elf/testdata/go-relocation-test-gcc441-x86.o)bin1884 -> 1884 bytes
-rw-r--r--src/pkg/debug/proc/proc_linux.go8
-rwxr-xr-xsrc/pkg/deps.bash10
-rw-r--r--src/pkg/encoding/pem/pem.go13
-rw-r--r--src/pkg/exec/Makefile3
-rw-r--r--src/pkg/exec/exec.go6
-rw-r--r--src/pkg/exec/lp_plan9.go51
-rw-r--r--src/pkg/exec/lp_unix.go2
-rw-r--r--src/pkg/exec/lp_windows.go23
-rw-r--r--src/pkg/exp/regexp/syntax/Makefile13
-rwxr-xr-xsrc/pkg/exp/regexp/syntax/make_perl_groups.pl103
-rw-r--r--src/pkg/exp/regexp/syntax/parse.go1220
-rw-r--r--src/pkg/exp/regexp/syntax/parse_test.go272
-rw-r--r--src/pkg/exp/regexp/syntax/perl_groups.go130
-rw-r--r--src/pkg/exp/regexp/syntax/regexp.go210
-rw-r--r--src/pkg/exp/template/Makefile12
-rw-r--r--src/pkg/exp/template/lex.go373
-rw-r--r--src/pkg/exp/template/lex_test.go129
-rw-r--r--src/pkg/exp/template/parse.go522
-rw-r--r--src/pkg/exp/template/parse_test.go176
-rw-r--r--src/pkg/flag/flag.go2
-rw-r--r--src/pkg/fmt/doc.go6
-rw-r--r--src/pkg/fmt/fmt_test.go62
-rw-r--r--src/pkg/fmt/format.go34
-rw-r--r--src/pkg/fmt/print.go46
-rw-r--r--src/pkg/fmt/scan.go11
-rw-r--r--src/pkg/fmt/scan_test.go4
-rw-r--r--src/pkg/go/build/Makefile2
-rw-r--r--src/pkg/go/build/build.go234
-rw-r--r--src/pkg/go/build/build_test.go76
-rw-r--r--src/pkg/go/build/cgotest/cgotest.go12
-rw-r--r--src/pkg/go/build/cgotest/file.go45
-rw-r--r--src/pkg/go/build/cmdtest/main.go12
-rw-r--r--src/pkg/go/build/dir.go13
-rw-r--r--src/pkg/go/build/pkgtest/pkgtest.go9
-rw-r--r--src/pkg/go/build/pkgtest/sqrt_386.s10
-rw-r--r--src/pkg/go/build/pkgtest/sqrt_amd64.s9
-rw-r--r--src/pkg/go/build/pkgtest/sqrt_arm.s10
-rw-r--r--src/pkg/go/parser/interface.go2
-rw-r--r--src/pkg/go/printer/nodes.go10
-rw-r--r--src/pkg/go/printer/testdata/statements.golden15
-rw-r--r--src/pkg/go/printer/testdata/statements.input13
-rw-r--r--src/pkg/go/scanner/scanner.go3
-rw-r--r--src/pkg/go/scanner/scanner_test.go6
-rw-r--r--src/pkg/go/types/exportdata.go8
-rw-r--r--src/pkg/go/types/gcimporter.go4
-rw-r--r--src/pkg/gob/codec_test.go2
-rw-r--r--src/pkg/gob/decode.go40
-rw-r--r--src/pkg/gob/decoder.go8
-rw-r--r--src/pkg/gob/encode.go2
-rw-r--r--src/pkg/gob/encoder.go2
-rw-r--r--src/pkg/gob/gobencdec_test.go8
-rw-r--r--src/pkg/gob/type.go4
-rw-r--r--src/pkg/hash/fnv/fnv.go17
-rw-r--r--src/pkg/http/cgi/child.go11
-rw-r--r--src/pkg/http/cgi/child_test.go8
-rw-r--r--src/pkg/http/cgi/host.go18
-rw-r--r--src/pkg/http/client.go14
-rw-r--r--src/pkg/http/client_test.go48
-rw-r--r--src/pkg/http/cookie.go112
-rw-r--r--src/pkg/http/cookie_test.go108
-rw-r--r--src/pkg/http/fs.go2
-rw-r--r--src/pkg/http/header.go3
-rw-r--r--src/pkg/http/header_test.go10
-rw-r--r--src/pkg/http/readrequest_test.go5
-rw-r--r--src/pkg/http/request.go133
-rw-r--r--src/pkg/http/requestwrite_test.go14
-rw-r--r--src/pkg/http/response.go14
-rw-r--r--src/pkg/http/reverseproxy.go4
-rw-r--r--src/pkg/http/reverseproxy_test.go4
-rw-r--r--src/pkg/http/serve_test.go15
-rw-r--r--src/pkg/http/server.go48
-rw-r--r--src/pkg/http/spdy/read.go90
-rw-r--r--src/pkg/http/spdy/spdy_test.go3
-rw-r--r--src/pkg/http/spdy/types.go57
-rw-r--r--src/pkg/http/spdy/write.go3
-rw-r--r--src/pkg/http/transport.go6
-rw-r--r--src/pkg/http/url.go17
-rw-r--r--src/pkg/image/draw/draw.go6
-rw-r--r--src/pkg/image/draw/draw_test.go2
-rw-r--r--src/pkg/image/gif/reader.go2
-rw-r--r--src/pkg/image/image_test.go79
-rw-r--r--src/pkg/io/io.go59
-rw-r--r--src/pkg/io/ioutil/ioutil.go2
-rw-r--r--src/pkg/mail/message.go113
-rw-r--r--src/pkg/mail/message_test.go20
-rw-r--r--src/pkg/mime/grammar.go4
-rw-r--r--src/pkg/mime/mediatype.go2
-rw-r--r--src/pkg/mime/multipart/formdata.go2
-rw-r--r--src/pkg/mime/multipart/formdata_test.go2
-rw-r--r--src/pkg/mime/multipart/multipart.go36
-rw-r--r--src/pkg/mime/multipart/multipart_test.go2
-rw-r--r--src/pkg/mime/multipart/writer.go6
-rw-r--r--src/pkg/mime/multipart/writer_test.go7
-rw-r--r--src/pkg/net/Makefile19
-rw-r--r--src/pkg/net/dnsclient.go367
-rw-r--r--src/pkg/net/dnsclient_unix.go262
-rw-r--r--src/pkg/net/dnsmsg.go8
-rw-r--r--src/pkg/net/dnsmsg_test.go7
-rw-r--r--src/pkg/net/dnsname_test.go4
-rw-r--r--src/pkg/net/fd_darwin.go2
-rw-r--r--src/pkg/net/interface.go36
-rw-r--r--src/pkg/net/interface_bsd.go65
-rw-r--r--src/pkg/net/interface_linux.go67
-rw-r--r--src/pkg/net/interface_stub.go28
-rw-r--r--src/pkg/net/interface_test.go32
-rw-r--r--src/pkg/net/interface_windows.go152
-rw-r--r--src/pkg/net/iprawsock.go2
-rw-r--r--src/pkg/net/ipsock.go8
-rw-r--r--src/pkg/net/lookup.go50
-rw-r--r--src/pkg/net/lookup_unix.go126
-rw-r--r--src/pkg/net/lookup_windows.go (renamed from src/pkg/net/resolv_windows.go)84
-rw-r--r--src/pkg/net/net.go2
-rw-r--r--src/pkg/net/net_test.go4
-rw-r--r--src/pkg/net/newpollserver.go14
-rw-r--r--src/pkg/net/sendfile_windows.go68
-rw-r--r--src/pkg/net/udpsock.go2
-rw-r--r--src/pkg/netchan/common.go4
-rw-r--r--src/pkg/netchan/export.go12
-rw-r--r--src/pkg/netchan/import.go8
-rw-r--r--src/pkg/os/Makefile1
-rw-r--r--src/pkg/os/error.go13
-rw-r--r--src/pkg/os/error_plan9.go1
-rw-r--r--src/pkg/os/exec.go6
-rw-r--r--src/pkg/os/exec_plan9.go23
-rw-r--r--src/pkg/os/exec_posix.go6
-rw-r--r--src/pkg/os/exec_windows.go2
-rw-r--r--src/pkg/os/file.go2
-rw-r--r--src/pkg/os/file_plan9.go69
-rw-r--r--src/pkg/os/os_test.go48
-rw-r--r--src/pkg/os/path_test.go6
-rw-r--r--src/pkg/os/path_windows.go2
-rw-r--r--src/pkg/os/stat_plan9.go17
-rw-r--r--src/pkg/os/str.go20
-rw-r--r--src/pkg/patch/textdiff.go10
-rw-r--r--src/pkg/rand/rand_test.go4
-rw-r--r--src/pkg/reflect/type.go4
-rw-r--r--src/pkg/reflect/value.go2
-rw-r--r--src/pkg/regexp/regexp.go20
-rw-r--r--src/pkg/rpc/client.go8
-rw-r--r--src/pkg/rpc/jsonrpc/all_test.go2
-rw-r--r--src/pkg/rpc/server.go14
-rw-r--r--src/pkg/rpc/server_test.go2
-rw-r--r--src/pkg/runtime/Makefile3
-rw-r--r--src/pkg/runtime/cgo/Makefile4
-rw-r--r--src/pkg/runtime/cgo/darwin_386.c72
-rw-r--r--src/pkg/runtime/cgo/darwin_amd64.c65
-rw-r--r--src/pkg/runtime/cgo/nacl_386.c19
-rw-r--r--src/pkg/runtime/cgo/util.c2
-rw-r--r--src/pkg/runtime/error.go5
-rw-r--r--src/pkg/runtime/linux/mem.c3
-rw-r--r--src/pkg/runtime/malloc.goc2
-rw-r--r--src/pkg/runtime/mem.go2
-rwxr-xr-xsrc/pkg/runtime/mkasmh.sh1
-rw-r--r--src/pkg/runtime/plan9/386/sys.s5
-rw-r--r--src/pkg/runtime/plan9/os.h30
-rw-r--r--src/pkg/runtime/plan9/thread.c30
-rw-r--r--src/pkg/runtime/pprof/pprof_test.go2
-rw-r--r--src/pkg/sort/search.go16
-rw-r--r--src/pkg/sort/search_test.go6
-rw-r--r--src/pkg/sort/sort.go64
-rw-r--r--src/pkg/sort/sort_test.go18
-rw-r--r--src/pkg/strconv/atoi.go6
-rw-r--r--src/pkg/strconv/quote.go6
-rw-r--r--src/pkg/strings/reader.go4
-rw-r--r--src/pkg/sync/mutex_test.go4
-rw-r--r--src/pkg/syscall/Makefile6
-rw-r--r--src/pkg/syscall/bpf_bsd.go167
-rw-r--r--src/pkg/syscall/exec_plan9.go36
-rw-r--r--src/pkg/syscall/exec_unix.go77
-rw-r--r--src/pkg/syscall/exec_windows.go26
-rw-r--r--src/pkg/syscall/lsf_linux.go78
-rwxr-xr-xsrc/pkg/syscall/mkall.sh5
-rwxr-xr-xsrc/pkg/syscall/mkerrors.sh10
-rwxr-xr-xsrc/pkg/syscall/mksyscall.pl17
-rwxr-xr-xsrc/pkg/syscall/mksyscall_windows.pl32
-rwxr-xr-xsrc/pkg/syscall/mksysnum_darwin.pl20
-rwxr-xr-xsrc/pkg/syscall/mksysnum_freebsd.pl2
-rwxr-xr-xsrc/pkg/syscall/mksysnum_linux.pl2
-rw-r--r--src/pkg/syscall/route_bsd.go4
-rw-r--r--src/pkg/syscall/sockcmsg_unix.go65
-rw-r--r--src/pkg/syscall/syscall.go65
-rw-r--r--src/pkg/syscall/syscall_bsd.go88
-rw-r--r--src/pkg/syscall/syscall_darwin.go4
-rw-r--r--src/pkg/syscall/syscall_darwin_386.go12
-rw-r--r--src/pkg/syscall/syscall_darwin_amd64.go12
-rw-r--r--src/pkg/syscall/syscall_freebsd_386.go12
-rw-r--r--src/pkg/syscall/syscall_freebsd_amd64.go12
-rw-r--r--src/pkg/syscall/syscall_linux.go8
-rw-r--r--src/pkg/syscall/syscall_linux_386.go8
-rw-r--r--src/pkg/syscall/syscall_linux_amd64.go2
-rw-r--r--src/pkg/syscall/syscall_linux_arm.go2
-rw-r--r--src/pkg/syscall/syscall_plan9.go20
-rw-r--r--src/pkg/syscall/syscall_unix.go68
-rw-r--r--src/pkg/syscall/syscall_windows.go4
-rw-r--r--src/pkg/syscall/types_linux.c11
-rw-r--r--src/pkg/syscall/types_plan9.c16
-rw-r--r--src/pkg/syscall/zerrors_darwin_386.go18
-rw-r--r--src/pkg/syscall/zerrors_darwin_amd64.go22
-rw-r--r--src/pkg/syscall/zerrors_linux_386.go102
-rw-r--r--src/pkg/syscall/zerrors_linux_amd64.go102
-rw-r--r--src/pkg/syscall/zerrors_linux_arm.go105
-rw-r--r--src/pkg/syscall/zerrors_plan9_386.go3
-rw-r--r--src/pkg/syscall/zsyscall_darwin_386.go27
-rw-r--r--src/pkg/syscall/zsyscall_darwin_amd64.go27
-rw-r--r--src/pkg/syscall/zsyscall_freebsd_386.go19
-rw-r--r--src/pkg/syscall/zsyscall_freebsd_amd64.go19
-rw-r--r--src/pkg/syscall/zsyscall_linux_amd64.go2
-rw-r--r--src/pkg/syscall/zsyscall_linux_arm.go2
-rw-r--r--src/pkg/syscall/zsyscall_windows_386.go47
-rw-r--r--src/pkg/syscall/zsysnum_darwin_386.go828
-rw-r--r--src/pkg/syscall/zsysnum_darwin_amd64.go828
-rw-r--r--src/pkg/syscall/ztypes_linux_386.go15
-rw-r--r--src/pkg/syscall/ztypes_linux_amd64.go15
-rw-r--r--src/pkg/syscall/ztypes_linux_arm.go15
-rw-r--r--src/pkg/syscall/ztypes_plan9_386.go1
-rw-r--r--src/pkg/syscall/ztypes_windows_386.go109
-rw-r--r--src/pkg/syslog/syslog_unix.go2
-rw-r--r--src/pkg/time/Makefile12
-rw-r--r--src/pkg/time/format.go2
-rw-r--r--src/pkg/time/sys.go13
-rw-r--r--src/pkg/time/sys_plan9.go18
-rw-r--r--src/pkg/time/sys_posix.go18
-rw-r--r--src/pkg/time/tick.go2
-rw-r--r--src/pkg/time/zoneinfo_plan9.go59
-rw-r--r--src/pkg/time/zoneinfo_posix.go62
-rw-r--r--src/pkg/time/zoneinfo_unix.go56
-rw-r--r--src/pkg/unicode/letter.go49
-rw-r--r--src/pkg/unicode/letter_test.go46
-rw-r--r--src/pkg/unicode/maketables.go305
-rw-r--r--src/pkg/unicode/tables.go634
-rw-r--r--src/pkg/websocket/client.go6
-rw-r--r--src/pkg/xml/read.go87
-rw-r--r--src/pkg/xml/read_test.go44
-rw-r--r--src/pkg/xml/xml.go23
-rw-r--r--src/pkg/xml/xml_test.go27
380 files changed, 11981 insertions, 4968 deletions
diff --git a/src/Make.ccmd b/src/Make.ccmd
index 88f647152..40cc3a0e8 100644
--- a/src/Make.ccmd
+++ b/src/Make.ccmd
@@ -9,7 +9,7 @@ TARG:=$(TARG).exe
endif
$(TARG): $(OFILES) $(LIB)
- $(HOST_LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) $(LIB) -lbio -l9 -lm $(HOST_LDFLAGS)
+ $(HOST_LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) $(LIB) -lmach -lbio -l9 -lm $(HOST_LDFLAGS)
$(OFILES): $(HFILES)
@@ -36,6 +36,7 @@ y.tab.c: y.tab.h
all: $(TARG)
+# Use $(PWD)/$*.c so that gdb shows full path in stack traces.
%.$(HOST_O): %.c
$(HOST_CC) $(HOST_CFLAGS) -c "$(PWD)/$*.c"
diff --git a/src/Make.clib b/src/Make.clib
index 25fe88463..4a7ea02d9 100644
--- a/src/Make.clib
+++ b/src/Make.clib
@@ -6,6 +6,7 @@
all: $(LIB)
+# Use $(PWD)/$*.c so that gdb shows full path in stack traces.
%.$(HOST_O): %.c
$(HOST_CC) $(HOST_CFLAGS) -c "$(PWD)/$*.c"
diff --git a/src/all-qemu.bash b/src/all-qemu.bash
index 6d5cd6edd..c7079ba13 100755
--- a/src/all-qemu.bash
+++ b/src/all-qemu.bash
@@ -8,7 +8,8 @@
export NOTEST=""
-NOTEST="$NOTEST big" # xxx
+NOTEST="$NOTEST big" # just slow
+NOTEST="$NOTEST go/build" # wants to run cgo
NOTEST="$NOTEST http net rpc syslog websocket" # no localhost network
NOTEST="$NOTEST os" # 64-bit seek fails
diff --git a/src/cmd/5c/txt.c b/src/cmd/5c/txt.c
index 4be1f6f62..a32387bc1 100644
--- a/src/cmd/5c/txt.c
+++ b/src/cmd/5c/txt.c
@@ -292,8 +292,7 @@ tmpreg(void)
void
regalloc(Node *n, Node *tn, Node *o)
{
- int i, j;
- static int lasti;
+ int i;
switch(tn->type->etype) {
case TCHAR:
@@ -310,16 +309,9 @@ regalloc(Node *n, Node *tn, Node *o)
if(i >= 0 && i < NREG)
goto out;
}
- j = lasti + REGRET+1;
- for(i=REGRET+1; i<NREG; i++) {
- if(j >= NREG)
- j = REGRET+1;
- if(reg[j] == 0) {
- i = j;
+ for(i=REGRET+1; i<=REGEXT-2; i++)
+ if(reg[i] == 0)
goto out;
- }
- j++;
- }
diag(tn, "out of fixed registers");
goto err;
@@ -331,16 +323,9 @@ regalloc(Node *n, Node *tn, Node *o)
if(i >= NREG && i < NREG+NFREG)
goto out;
}
- j = 0*2 + NREG;
- for(i=NREG; i<NREG+NFREG; i++) {
- if(j >= NREG+NFREG)
- j = NREG;
- if(reg[j] == 0) {
- i = j;
+ for(i=NREG; i<NREG+NFREG; i++)
+ if(reg[i] == 0)
goto out;
- }
- j++;
- }
diag(tn, "out of float registers");
goto err;
}
@@ -350,9 +335,6 @@ err:
return;
out:
reg[i]++;
-/* lasti++; *** StrongARM does register forwarding */
- if(lasti >= 5)
- lasti = 0;
nodreg(n, tn, i);
}
diff --git a/src/cmd/5g/ggen.c b/src/cmd/5g/ggen.c
index 0bc1b38fc..d5b00b34d 100644
--- a/src/cmd/5g/ggen.c
+++ b/src/cmd/5g/ggen.c
@@ -22,6 +22,32 @@ defframe(Prog *ptxt)
maxstksize = 0;
}
+// Sweep the prog list to mark any used nodes.
+void
+markautoused(Prog* p)
+{
+ for (; p; p = p->link) {
+ if (p->from.name == D_AUTO && p->from.node)
+ p->from.node->used++;
+
+ if (p->to.name == D_AUTO && p->to.node)
+ p->to.node->used++;
+ }
+}
+
+// Fixup instructions after compactframe has moved all autos around.
+void
+fixautoused(Prog* p)
+{
+ for (; p; p = p->link) {
+ if (p->from.name == D_AUTO && p->from.node)
+ p->from.offset += p->from.node->stkdelta;
+
+ if (p->to.name == D_AUTO && p->to.node)
+ p->to.offset += p->to.node->stkdelta;
+ }
+}
+
/*
* generate:
* call f
@@ -147,13 +173,13 @@ cgen_callinter(Node *n, Node *res, int proc)
nodindreg(&nodsp, types[tptr], REGSP);
nodsp.xoffset = 4;
nodo.xoffset += widthptr;
- cgen(&nodo, &nodsp); // 4(SP) = 8(REG) -- i.s
+ cgen(&nodo, &nodsp); // 4(SP) = 4(REG) -- i.data
nodo.xoffset -= widthptr;
- cgen(&nodo, &nodr); // REG = 0(REG) -- i.m
+ cgen(&nodo, &nodr); // REG = 0(REG) -- i.tab
nodo.xoffset = n->left->xoffset + 3*widthptr + 8;
- cgen(&nodo, &nodr); // REG = 32+offset(REG) -- i.m->fun[f]
+ cgen(&nodo, &nodr); // REG = 20+offset(REG) -- i.tab->fun[f]
// BOTCH nodr.type = fntype;
nodr.type = n->left->type;
diff --git a/src/cmd/5g/gobj.c b/src/cmd/5g/gobj.c
index acece6c0d..27c8be67d 100644
--- a/src/cmd/5g/gobj.c
+++ b/src/cmd/5g/gobj.c
@@ -182,6 +182,8 @@ dumpfuncs(void)
// fix up pc
pcloc = 0;
for(pl=plist; pl!=nil; pl=pl->link) {
+ if(isblank(pl->name))
+ continue;
for(p=pl->firstpc; p!=P; p=p->link) {
p->loc = pcloc;
if(p->as != ADATA && p->as != AGLOBL)
@@ -191,6 +193,8 @@ dumpfuncs(void)
// put out functions
for(pl=plist; pl!=nil; pl=pl->link) {
+ if(isblank(pl->name))
+ continue;
if(debug['S']) {
s = S;
diff --git a/src/cmd/5g/gsubr.c b/src/cmd/5g/gsubr.c
index bc39912ea..2d9218461 100644
--- a/src/cmd/5g/gsubr.c
+++ b/src/cmd/5g/gsubr.c
@@ -102,6 +102,19 @@ patch(Prog *p, Prog *to)
p->to.offset = to->loc;
}
+Prog*
+unpatch(Prog *p)
+{
+ Prog *q;
+
+ if(p->to.type != D_BRANCH)
+ fatal("unpatch: not a branch");
+ q = p->to.branch;
+ p->to.branch = P;
+ p->to.offset = 0;
+ return q;
+}
+
/*
* start a new Prog list.
*/
@@ -125,6 +138,64 @@ newplist(void)
}
void
+clearstk(void)
+{
+ Plist *pl;
+ Prog *p, *p1, *p2, *p3;
+ Node dst, end, zero, con;
+
+ if(plast->firstpc->to.offset <= 0)
+ return;
+
+ // reestablish context for inserting code
+ // at beginning of function.
+ pl = plast;
+ p1 = pl->firstpc;
+ p2 = p1->link;
+ pc = mal(sizeof(*pc));
+ clearp(pc);
+ p1->link = pc;
+
+ // zero stack frame
+
+ // MOVW $4(SP), R1
+ nodreg(&dst, types[tptr], 1);
+ p = gins(AMOVW, N, &dst);
+ p->from.type = D_CONST;
+ p->from.reg = REGSP;
+ p->from.offset = 4;
+
+ // MOVW $n(R1), R2
+ nodreg(&end, types[tptr], 2);
+ p = gins(AMOVW, N, &end);
+ p->from.type = D_CONST;
+ p->from.reg = 1;
+ p->from.offset = p1->to.offset;
+
+ // MOVW $0, R3
+ nodreg(&zero, types[TUINT32], 3);
+ nodconst(&con, types[TUINT32], 0);
+ gmove(&con, &zero);
+
+ // L:
+ // MOVW.P R3, 0(R1) +4
+ // CMP R1, R2
+ // BNE L
+ p = gins(AMOVW, &zero, &dst);
+ p->to.type = D_OREG;
+ p->to.offset = 4;
+ p->scond |= C_PBIT;
+ p3 = p;
+ p = gins(ACMP, &dst, N);
+ raddr(&end, p);
+ patch(gbranch(ABNE, T), p3);
+
+ // continue with original code.
+ gins(ANOP, N, N)->link = p2;
+ pc = P;
+}
+
+void
gused(Node *n)
{
gins(ANOP, n, N); // used
diff --git a/src/cmd/5g/reg.c b/src/cmd/5g/reg.c
index 5fba02c9e..77d0a87eb 100644
--- a/src/cmd/5g/reg.c
+++ b/src/cmd/5g/reg.c
@@ -1525,6 +1525,7 @@ noreturn(Prog *p)
symlist[1] = pkglookup("panicslice", runtimepkg);
symlist[2] = pkglookup("throwinit", runtimepkg);
symlist[3] = pkglookup("panic", runtimepkg);
+ symlist[4] = pkglookup("panicwrap", runtimepkg);
}
s = p->to.sym;
@@ -1555,27 +1556,27 @@ dumpone(Reg *r)
r->regdiff.b[z] |
r->act.b[z] |
0;
-// if(bany(&bit)) {
-// print("\t");
-// if(bany(&r->set))
-// print(" s:%Q", r->set);
-// if(bany(&r->use1))
-// print(" u1:%Q", r->use1);
-// if(bany(&r->use2))
-// print(" u2:%Q", r->use2);
-// if(bany(&r->refbehind))
-// print(" rb:%Q ", r->refbehind);
-// if(bany(&r->refahead))
-// print(" ra:%Q ", r->refahead);
-// if(bany(&r->calbehind))
-// print("cb:%Q ", r->calbehind);
-// if(bany(&r->calahead))
-// print(" ca:%Q ", r->calahead);
-// if(bany(&r->regdiff))
-// print(" d:%Q ", r->regdiff);
-// if(bany(&r->act))
-// print(" a:%Q ", r->act);
-// }
+ if(bany(&bit)) {
+ print("\t");
+ if(bany(&r->set))
+ print(" s:%Q", r->set);
+ if(bany(&r->use1))
+ print(" u1:%Q", r->use1);
+ if(bany(&r->use2))
+ print(" u2:%Q", r->use2);
+ if(bany(&r->refbehind))
+ print(" rb:%Q ", r->refbehind);
+ if(bany(&r->refahead))
+ print(" ra:%Q ", r->refahead);
+ if(bany(&r->calbehind))
+ print("cb:%Q ", r->calbehind);
+ if(bany(&r->calahead))
+ print(" ca:%Q ", r->calahead);
+ if(bany(&r->regdiff))
+ print(" d:%Q ", r->regdiff);
+ if(bany(&r->act))
+ print(" a:%Q ", r->act);
+ }
print("\n");
}
diff --git a/src/cmd/5l/noop.c b/src/cmd/5l/noop.c
index e7c2db5f2..eb44344f4 100644
--- a/src/cmd/5l/noop.c
+++ b/src/cmd/5l/noop.c
@@ -45,8 +45,6 @@ static Sym* sym_divu;
static Sym* sym_mod;
static Sym* sym_modu;
-static void setdiv(int);
-
void
noops(void)
{
@@ -93,7 +91,6 @@ noops(void)
if(prog_div == P)
initdiv();
cursym->text->mark &= ~LEAF;
- setdiv(p->as);
continue;
case ANOP:
@@ -533,27 +530,6 @@ initdiv(void)
}
}
-static void
-setdiv(int as)
-{
- Prog *p = nil;
-
- switch(as){
- case ADIV:
- p = prog_div;
- break;
- case ADIVU:
- p = prog_divu;
- break;
- case AMOD:
- p = prog_mod;
- break;
- case AMODU:
- p = prog_modu;
- break;
- }
-}
-
void
nocache(Prog *p)
{
diff --git a/src/cmd/6c/cgen.c b/src/cmd/6c/cgen.c
index 90394884f..7aa4aa976 100644
--- a/src/cmd/6c/cgen.c
+++ b/src/cmd/6c/cgen.c
@@ -1544,7 +1544,7 @@ sugen(Node *n, Node *nn, int32 w)
nod0.addable = 0;
nod0.right = l;
- /* prtree(&nod0, "hand craft"); /* */
+ // prtree(&nod0, "hand craft");
cgen(&nod0, Z);
}
break;
diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c
index 5260335df..9e7fbab0d 100644
--- a/src/cmd/6g/ggen.c
+++ b/src/cmd/6g/ggen.c
@@ -18,6 +18,32 @@ defframe(Prog *ptxt)
ptxt->to.offset |= rnd(stksize+maxarg, widthptr);
}
+// Sweep the prog list to mark any used nodes.
+void
+markautoused(Prog* p)
+{
+ for (; p; p = p->link) {
+ if (p->from.type == D_AUTO && p->from.node)
+ p->from.node->used++;
+
+ if (p->to.type == D_AUTO && p->to.node)
+ p->to.node->used++;
+ }
+}
+
+// Fixup instructions after compactframe has moved all autos around.
+void
+fixautoused(Prog* p)
+{
+ for (; p; p = p->link) {
+ if (p->from.type == D_AUTO && p->from.node)
+ p->from.offset += p->from.node->stkdelta;
+
+ if (p->to.type == D_AUTO && p->to.node)
+ p->to.offset += p->to.node->stkdelta;
+ }
+}
+
/*
* generate:
@@ -102,13 +128,13 @@ cgen_callinter(Node *n, Node *res, int proc)
nodindreg(&nodsp, types[tptr], D_SP);
nodo.xoffset += widthptr;
- cgen(&nodo, &nodsp); // 0(SP) = 8(REG) -- i.s
+ cgen(&nodo, &nodsp); // 0(SP) = 8(REG) -- i.data
nodo.xoffset -= widthptr;
- cgen(&nodo, &nodr); // REG = 0(REG) -- i.m
+ cgen(&nodo, &nodr); // REG = 0(REG) -- i.tab
nodo.xoffset = n->left->xoffset + 3*widthptr + 8;
- cgen(&nodo, &nodr); // REG = 32+offset(REG) -- i.m->fun[f]
+ cgen(&nodo, &nodr); // REG = 32+offset(REG) -- i.tab->fun[f]
// BOTCH nodr.type = fntype;
nodr.type = n->left->type;
diff --git a/src/cmd/6g/gobj.c b/src/cmd/6g/gobj.c
index 507764a3b..ba8a4870e 100644
--- a/src/cmd/6g/gobj.c
+++ b/src/cmd/6g/gobj.c
@@ -228,6 +228,8 @@ dumpfuncs(void)
// fix up pc
pcloc = 0;
for(pl=plist; pl!=nil; pl=pl->link) {
+ if(isblank(pl->name))
+ continue;
for(p=pl->firstpc; p!=P; p=p->link) {
p->loc = pcloc;
if(p->as != ADATA && p->as != AGLOBL)
@@ -237,6 +239,8 @@ dumpfuncs(void)
// put out functions
for(pl=plist; pl!=nil; pl=pl->link) {
+ if(isblank(pl->name))
+ continue;
if(debug['S']) {
s = S;
diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c
index ae6ae5765..211915f54 100644
--- a/src/cmd/6g/gsubr.c
+++ b/src/cmd/6g/gsubr.c
@@ -98,6 +98,19 @@ patch(Prog *p, Prog *to)
p->to.offset = to->loc;
}
+Prog*
+unpatch(Prog *p)
+{
+ Prog *q;
+
+ if(p->to.type != D_BRANCH)
+ fatal("unpatch: not a branch");
+ q = p->to.branch;
+ p->to.branch = P;
+ p->to.offset = 0;
+ return q;
+}
+
/*
* start a new Prog list.
*/
@@ -121,6 +134,44 @@ newplist(void)
}
void
+clearstk(void)
+{
+ Plist *pl;
+ Prog *p1, *p2;
+ Node sp, di, cx, con, ax;
+
+ if((uint32)plast->firstpc->to.offset <= 0)
+ return;
+
+ // reestablish context for inserting code
+ // at beginning of function.
+ pl = plast;
+ p1 = pl->firstpc;
+ p2 = p1->link;
+ pc = mal(sizeof(*pc));
+ clearp(pc);
+ p1->link = pc;
+
+ // zero stack frame
+ nodreg(&sp, types[tptr], D_SP);
+ nodreg(&di, types[tptr], D_DI);
+ nodreg(&cx, types[TUINT64], D_CX);
+ nodconst(&con, types[TUINT64], (uint32)p1->to.offset / widthptr);
+ gins(ACLD, N, N);
+ gins(AMOVQ, &sp, &di);
+ gins(AMOVQ, &con, &cx);
+ nodconst(&con, types[TUINT64], 0);
+ nodreg(&ax, types[TUINT64], D_AX);
+ gins(AMOVQ, &con, &ax);
+ gins(AREP, N, N);
+ gins(ASTOSQ, N, N);
+
+ // continue with original code.
+ gins(ANOP, N, N)->link = p2;
+ pc = P;
+}
+
+void
gused(Node *n)
{
gins(ANOP, n, N); // used
diff --git a/src/cmd/6g/reg.c b/src/cmd/6g/reg.c
index af9b29cbc..4d4263047 100644
--- a/src/cmd/6g/reg.c
+++ b/src/cmd/6g/reg.c
@@ -1677,6 +1677,7 @@ noreturn(Prog *p)
symlist[1] = pkglookup("panicslice", runtimepkg);
symlist[2] = pkglookup("throwinit", runtimepkg);
symlist[3] = pkglookup("panic", runtimepkg);
+ symlist[4] = pkglookup("panicwrap", runtimepkg);
}
s = p->to.sym;
diff --git a/src/cmd/8a/l.s b/src/cmd/8a/l.s
deleted file mode 100644
index 4e193a31a..000000000
--- a/src/cmd/8a/l.s
+++ /dev/null
@@ -1,734 +0,0 @@
-// Inferno utils/8a/l.s
-// http://code.google.com/p/inferno-os/source/browse/utils/8a/l.s
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-/*
- * Memory and machine-specific definitions. Used in C and assembler.
- */
-
-/*
- * Sizes
- */
-#define BI2BY 8 /* bits per byte */
-#define BI2WD 32 /* bits per word */
-#define BY2WD 4 /* bytes per word */
-#define BY2PG 4096 /* bytes per page */
-#define WD2PG (BY2PG/BY2WD) /* words per page */
-#define PGSHIFT 12 /* log(BY2PG) */
-#define PGROUND(s) (((s)+(BY2PG-1))&~(BY2PG-1))
-
-#define MAXMACH 1 /* max # cpus system can run */
-
-/*
- * Time
- */
-#define HZ (20) /* clock frequency */
-#define MS2HZ (1000/HZ) /* millisec per clock tick */
-#define TK2SEC(t) ((t)/HZ) /* ticks to seconds */
-#define TK2MS(t) ((((ulong)(t))*1000)/HZ) /* ticks to milliseconds */
-#define MS2TK(t) ((((ulong)(t))*HZ)/1000) /* milliseconds to ticks */
-
-/*
- * Fundamental addresses
- */
-
-/*
- * Address spaces
- *
- * User is at 0-2GB
- * Kernel is at 2GB-4GB
- *
- * To avoid an extra page map, both the user stack (USTKTOP) and
- * the temporary user stack (TSTKTOP) should be in the the same
- * 4 meg.
- */
-#define UZERO 0 /* base of user address space */
-#define UTZERO (UZERO+BY2PG) /* first address in user text */
-#define KZERO 0x80000000 /* base of kernel address space */
-#define KTZERO KZERO /* first address in kernel text */
-#define USERADDR 0xC0000000 /* struct User */
-#define UREGADDR (USERADDR+BY2PG-4*19)
-#define TSTKTOP USERADDR /* end of new stack in sysexec */
-#define TSTKSIZ 10
-#define USTKTOP (TSTKTOP-TSTKSIZ*BY2PG) /* byte just beyond user stack */
-#define USTKSIZE (16*1024*1024 - TSTKSIZ*BY2PG) /* size of user stack */
-#define ROMBIOS (KZERO|0xF0000)
-
-#define MACHSIZE 4096
-
-#define isphys(x) (((ulong)x)&KZERO)
-
-/*
- * known 80386 segments (in GDT) and their selectors
- */
-#define NULLSEG 0 /* null segment */
-#define KDSEG 1 /* kernel data/stack */
-#define KESEG 2 /* kernel executable */
-#define UDSEG 3 /* user data/stack */
-#define UESEG 4 /* user executable */
-#define TSSSEG 5 /* task segment */
-
-#define SELGDT (0<<3) /* selector is in gdt */
-#define SELLDT (1<<3) /* selector is in ldt */
-
-#define SELECTOR(i, t, p) (((i)<<3) | (t) | (p))
-
-#define NULLSEL SELECTOR(NULLSEG, SELGDT, 0)
-#define KESEL SELECTOR(KESEG, SELGDT, 0)
-#define KDSEL SELECTOR(KDSEG, SELGDT, 0)
-#define UESEL SELECTOR(UESEG, SELGDT, 3)
-#define UDSEL SELECTOR(UDSEG, SELGDT, 3)
-#define TSSSEL SELECTOR(TSSSEG, SELGDT, 0)
-
-/*
- * fields in segment descriptors
- */
-#define SEGDATA (0x10<<8) /* data/stack segment */
-#define SEGEXEC (0x18<<8) /* executable segment */
-#define SEGTSS (0x9<<8) /* TSS segment */
-#define SEGCG (0x0C<<8) /* call gate */
-#define SEGIG (0x0E<<8) /* interrupt gate */
-#define SEGTG (0x0F<<8) /* task gate */
-#define SEGTYPE (0x1F<<8)
-
-#define SEGP (1<<15) /* segment present */
-#define SEGPL(x) ((x)<<13) /* priority level */
-#define SEGB (1<<22) /* granularity 1==4k (for expand-down) */
-#define SEGG (1<<23) /* granularity 1==4k (for other) */
-#define SEGE (1<<10) /* expand down */
-#define SEGW (1<<9) /* writable (for data/stack) */
-#define SEGR (1<<9) /* readable (for code) */
-#define SEGD (1<<22) /* default 1==32bit (for code) */
-
-/*
- * virtual MMU
- */
-#define PTEMAPMEM (1024*1024) /* ??? */
-#define SEGMAPSIZE 16 /* ??? */
-#define PTEPERTAB (PTEMAPMEM/BY2PG) /* ??? */
-#define PPN(x) ((x)&~(BY2PG-1))
-
-/*
- * physical MMU
- */
-#define PTEVALID (1<<0)
-#define PTEUNCACHED 0 /* everything is uncached */
-#define PTEWRITE (1<<1)
-#define PTERONLY (0<<1)
-#define PTEKERNEL (0<<2)
-#define PTEUSER (1<<2)
-
-/*
- * flag register bits that we care about
- */
-#define IFLAG 0x200
-
-#define OP16 BYTE $0x66
-
-/*
- * about to walk all over ms/dos - turn off interrupts
- */
-TEXT origin(SB),$0
-
- CLI
-
-#ifdef BOOT
-/*
- * This part of l.s is used only in the boot kernel.
- * It assumes that we are in real address mode, i.e.,
- * that we look like an 8086.
- */
-/*
- * relocate everything to a half meg and jump there
- * - looks wierd because it is being assembled by a 32 bit
- * assembler for a 16 bit world
- */
- MOVL $0,BX
- INCL BX
- SHLL $15,BX
- MOVL BX,CX
- MOVW BX,ES
- MOVL $0,SI
- MOVL SI,DI
- CLD; REP; MOVSL
-/* JMPFAR 0X8000:$lowcore(SB) /**/
- BYTE $0xEA
- WORD $lowcore(SB)
- WORD $0X8000
-
-TEXT lowcore(SB),$0
-
-/*
- * now that we're in low core, update the DS
- */
-
- MOVW BX,DS
-
-/*
- * goto protected mode
- */
-/* MOVL tgdtptr(SB),GDTR /**/
- BYTE $0x0f
- BYTE $0x01
- BYTE $0x16
- WORD $tgdtptr(SB)
- MOVL CR0,AX
- ORL $1,AX
- MOVL AX,CR0
-
-/*
- * clear prefetch queue (wierd code to avoid optimizations)
- */
- CLC
- JCC flush
- MOVL AX,AX
-flush:
-
-/*
- * set all segs
- */
-/* MOVW $SELECTOR(1, SELGDT, 0),AX /**/
- BYTE $0xc7
- BYTE $0xc0
- WORD $SELECTOR(1, SELGDT, 0)
- MOVW AX,DS
- MOVW AX,SS
- MOVW AX,ES
- MOVW AX,FS
- MOVW AX,GS
-
-/* JMPFAR SELECTOR(2, SELGDT, 0):$mode32bit(SB) /**/
- BYTE $0x66
- BYTE $0xEA
- LONG $mode32bit-KZERO(SB)
- WORD $SELECTOR(2, SELGDT, 0)
-
-TEXT mode32bit(SB),$0
-
-#endif BOOT
-
- /*
- * Clear BSS
- */
- LEAL edata-KZERO(SB),SI
- MOVL SI,DI
- ADDL $4,DI
- MOVL $0,AX
- MOVL AX,(SI)
- LEAL end-KZERO(SB),CX
- SUBL DI,CX
- SHRL $2,CX
- CLD; REP; MOVSL
-
- /*
- * make a bottom level page table page that maps the first
- * 16 meg of physical memory
- */
- LEAL tpt-KZERO(SB),AX /* get phys addr of temporary page table */
- ADDL $(BY2PG-1),AX /* must be page aligned */
- ANDL $(~(BY2PG-1)),AX /* ... */
- MOVL $(4*1024),CX /* pte's per page */
- MOVL $((((4*1024)-1)<<PGSHIFT)|PTEVALID|PTEKERNEL|PTEWRITE),BX
-setpte:
- MOVL BX,-4(AX)(CX*4)
- SUBL $(1<<PGSHIFT),BX
- LOOP setpte
-
- /*
- * make a top level page table page that maps the first
- * 16 meg of memory to 0 thru 16meg and to KZERO thru KZERO+16meg
- */
- MOVL AX,BX
- ADDL $(4*BY2PG),AX
- ADDL $(PTEVALID|PTEKERNEL|PTEWRITE),BX
- MOVL BX,0(AX)
- MOVL BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+0)(AX)
- ADDL $BY2PG,BX
- MOVL BX,4(AX)
- MOVL BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+4)(AX)
- ADDL $BY2PG,BX
- MOVL BX,8(AX)
- MOVL BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+8)(AX)
- ADDL $BY2PG,BX
- MOVL BX,12(AX)
- MOVL BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+12)(AX)
-
- /*
- * point processor to top level page & turn on paging
- */
- MOVL AX,CR3
- MOVL CR0,AX
- ORL $0X80000000,AX
- ANDL $~(0x8|0x2),AX /* TS=0, MP=0 */
- MOVL AX,CR0
-
- /*
- * use a jump to an absolute location to get the PC into
- * KZERO.
- */
- LEAL tokzero(SB),AX
- JMP* AX
-
-TEXT tokzero(SB),$0
-
- /*
- * stack and mach
- */
- MOVL $mach0(SB),SP
- MOVL SP,m(SB)
- MOVL $0,0(SP)
- ADDL $(MACHSIZE-4),SP /* start stack under machine struct */
- MOVL $0, u(SB)
-
- /*
- * clear flags
- */
- MOVL $0,AX
- PUSHL AX
- POPFL
-
- CALL main(SB)
-
-loop:
- JMP loop
-
-GLOBL mach0+0(SB), $MACHSIZE
-GLOBL u(SB), $4
-GLOBL m(SB), $4
-GLOBL tpt(SB), $(BY2PG*6)
-
-/*
- * gdt to get us to 32-bit/segmented/unpaged mode
- */
-TEXT tgdt(SB),$0
-
- /* null descriptor */
- LONG $0
- LONG $0
-
- /* data segment descriptor for 4 gigabytes (PL 0) */
- LONG $(0xFFFF)
- LONG $(SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(0)|SEGDATA|SEGW)
-
- /* exec segment descriptor for 4 gigabytes (PL 0) */
- LONG $(0xFFFF)
- LONG $(SEGG|SEGD|(0xF<<16)|SEGP|SEGPL(0)|SEGEXEC|SEGR)
-
-/*
- * pointer to initial gdt
- */
-TEXT tgdtptr(SB),$0
-
- WORD $(3*8)
- LONG $tgdt-KZERO(SB)
-
-/*
- * input a byte
- */
-TEXT inb(SB),$0
-
- MOVL p+0(FP),DX
- XORL AX,AX
- INB
- RET
-
-/*
- * output a byte
- */
-TEXT outb(SB),$0
-
- MOVL p+0(FP),DX
- MOVL b+4(FP),AX
- OUTB
- RET
-
-/*
- * input a string of shorts from a port
- */
-TEXT inss(SB),$0
- MOVL p+0(FP),DX
- MOVL a+4(FP),DI
- MOVL c+8(FP),CX
- CLD; REP; OP16; INSL
- RET
-
-/*
- * output a string of shorts to a port
- */
-TEXT outss(SB),$0
- MOVL p+0(FP),DX
- MOVL a+4(FP),SI
- MOVL c+8(FP),CX
- CLD; REP; OP16; OUTSL
- RET
-
-/*
- * test and set
- */
-TEXT tas(SB),$0
- MOVL $0xdeadead,AX
- MOVL l+0(FP),BX
- XCHGL AX,(BX)
- RET
-
-/*
- * routines to load/read various system registers
- */
-GLOBL idtptr(SB),$6
-TEXT putidt(SB),$0 /* interrupt descriptor table */
- MOVL t+0(FP),AX
- MOVL AX,idtptr+2(SB)
- MOVL l+4(FP),AX
- MOVW AX,idtptr(SB)
- MOVL idtptr(SB),IDTR
- RET
-
-GLOBL gdtptr(SB),$6
-TEXT putgdt(SB),$0 /* global descriptor table */
- MOVL t+0(FP),AX
- MOVL AX,gdtptr+2(SB)
- MOVL l+4(FP),AX
- MOVW AX,gdtptr(SB)
- MOVL gdtptr(SB),GDTR
- RET
-
-TEXT putcr3(SB),$0 /* top level page table pointer */
- MOVL t+0(FP),AX
- MOVL AX,CR3
- RET
-
-TEXT puttr(SB),$0 /* task register */
- MOVL t+0(FP),AX
- MOVW AX,TASK
- RET
-
-TEXT getcr0(SB),$0 /* coprocessor bits */
- MOVL CR0,AX
- RET
-
-TEXT getcr2(SB),$0 /* fault address */
- MOVL CR2,AX
- RET
-
-#define FPOFF\
- WAIT;\
- MOVL CR0,AX;\
- ORL $0x4,AX /* EM=1 */;\
- MOVL AX,CR0
-
-#define FPON\
- MOVL CR0,AX;\
- ANDL $~0x4,AX /* EM=0 */;\
- MOVL AX,CR0
-
-TEXT fpoff(SB),$0 /* turn off floating point */
- FPOFF
- RET
-
-TEXT fpinit(SB),$0 /* turn on & init the floating point */
- FPON
- FINIT
- WAIT
- PUSHW $0x0330
- FLDCW 0(SP) /* ignore underflow/precision, signal others */
- POPW AX
- WAIT
- RET
-
-TEXT fpsave(SB),$0 /* save floating point state and turn off */
- MOVL p+0(FP),AX
- WAIT
- FSAVE 0(AX)
- FPOFF
- RET
-
-TEXT fprestore(SB),$0 /* turn on floating point and restore regs */
- FPON
- MOVL p+0(FP),AX
- FRSTOR 0(AX)
- WAIT
- RET
-
-TEXT fpstatus(SB),$0 /* get floating point status */
- FSTSW AX
- RET
-
-/*
- * special traps
- */
-TEXT intr0(SB),$0
- PUSHL $0
- PUSHL $0
- JMP intrcommon
-TEXT intr1(SB),$0
- PUSHL $0
- PUSHL $1
- JMP intrcommon
-TEXT intr2(SB),$0
- PUSHL $0
- PUSHL $2
- JMP intrcommon
-TEXT intr3(SB),$0
- PUSHL $0
- PUSHL $3
- JMP intrcommon
-TEXT intr4(SB),$0
- PUSHL $0
- PUSHL $4
- JMP intrcommon
-TEXT intr5(SB),$0
- PUSHL $0
- PUSHL $5
- JMP intrcommon
-TEXT intr6(SB),$0
- PUSHL $0
- PUSHL $6
- JMP intrcommon
-TEXT intr7(SB),$0
- PUSHL $0
- PUSHL $7
- JMP intrcommon
-TEXT intr8(SB),$0
- PUSHL $8
- JMP intrscommon
-TEXT intr9(SB),$0
- PUSHL $0
- PUSHL $9
- JMP intrcommon
-TEXT intr10(SB),$0
- PUSHL $10
- JMP intrscommon
-TEXT intr11(SB),$0
- PUSHL $11
- JMP intrscommon
-TEXT intr12(SB),$0
- PUSHL $12
- JMP intrscommon
-TEXT intr13(SB),$0
- PUSHL $13
- JMP intrscommon
-TEXT intr14(SB),$0
- PUSHL $14
- JMP intrscommon
-TEXT intr15(SB),$0
- PUSHL $0
- PUSHL $15
- JMP intrcommon
-TEXT intr16(SB),$0
- PUSHL $0
- PUSHL $16
- JMP intrcommon
-TEXT intr24(SB),$0
- PUSHL $0
- PUSHL $24
- JMP intrcommon
-TEXT intr25(SB),$0
- PUSHL $0
- PUSHL $25
- JMP intrcommon
-TEXT intr26(SB),$0
- PUSHL $0
- PUSHL $26
- JMP intrcommon
-TEXT intr27(SB),$0
- PUSHL $0
- PUSHL $27
- JMP intrcommon
-TEXT intr28(SB),$0
- PUSHL $0
- PUSHL $28
- JMP intrcommon
-TEXT intr29(SB),$0
- PUSHL $0
- PUSHL $29
- JMP intrcommon
-TEXT intr30(SB),$0
- PUSHL $0
- PUSHL $30
- JMP intrcommon
-TEXT intr31(SB),$0
- PUSHL $0
- PUSHL $31
- JMP intrcommon
-TEXT intr32(SB),$0
- PUSHL $0
- PUSHL $16
- JMP intrcommon
-TEXT intr33(SB),$0
- PUSHL $0
- PUSHL $33
- JMP intrcommon
-TEXT intr34(SB),$0
- PUSHL $0
- PUSHL $34
- JMP intrcommon
-TEXT intr35(SB),$0
- PUSHL $0
- PUSHL $35
- JMP intrcommon
-TEXT intr36(SB),$0
- PUSHL $0
- PUSHL $36
- JMP intrcommon
-TEXT intr37(SB),$0
- PUSHL $0
- PUSHL $37
- JMP intrcommon
-TEXT intr38(SB),$0
- PUSHL $0
- PUSHL $38
- JMP intrcommon
-TEXT intr39(SB),$0
- PUSHL $0
- PUSHL $39
- JMP intrcommon
-TEXT intr64(SB),$0
- PUSHL $0
- PUSHL $64
- JMP intrcommon
-TEXT intrbad(SB),$0
- PUSHL $0
- PUSHL $0x1ff
- JMP intrcommon
-
-intrcommon:
- PUSHL DS
- PUSHL ES
- PUSHL FS
- PUSHL GS
- PUSHAL
- MOVL $(KDSEL),AX
- MOVW AX,DS
- MOVW AX,ES
- LEAL 0(SP),AX
- PUSHL AX
- CALL trap(SB)
- POPL AX
- POPAL
- POPL GS
- POPL FS
- POPL ES
- POPL DS
- ADDL $8,SP /* error code and trap type */
- IRETL
-
-intrscommon:
- PUSHL DS
- PUSHL ES
- PUSHL FS
- PUSHL GS
- PUSHAL
- MOVL $(KDSEL),AX
- MOVW AX,DS
- MOVW AX,ES
- LEAL 0(SP),AX
- PUSHL AX
- CALL trap(SB)
- POPL AX
- POPAL
- POPL GS
- POPL FS
- POPL ES
- POPL DS
- ADDL $8,SP /* error code and trap type */
- IRETL
-
-/*
- * interrupt level is interrupts on or off
- */
-TEXT spllo(SB),$0
- PUSHFL
- POPL AX
- STI
- RET
-
-TEXT splhi(SB),$0
- PUSHFL
- POPL AX
- CLI
- RET
-
-TEXT splx(SB),$0
- MOVL s+0(FP),AX
- PUSHL AX
- POPFL
- RET
-
-/*
- * do nothing whatsoever till interrupt happens
- */
-TEXT idle(SB),$0
- HLT
- RET
-
-/*
- * label consists of a stack pointer and a PC
- */
-TEXT gotolabel(SB),$0
- MOVL l+0(FP),AX
- MOVL 0(AX),SP /* restore sp */
- MOVL 4(AX),AX /* put return pc on the stack */
- MOVL AX,0(SP)
- MOVL $1,AX /* return 1 */
- RET
-
-TEXT setlabel(SB),$0
- MOVL l+0(FP),AX
- MOVL SP,0(AX) /* store sp */
- MOVL 0(SP),BX /* store return pc */
- MOVL BX,4(AX)
- MOVL $0,AX /* return 0 */
- RET
-
-/*
- * Used to get to the first process.
- * Set up an interrupt return frame and IRET to user level.
- */
-TEXT touser(SB),$0
- PUSHL $(UDSEL) /* old ss */
- PUSHL $(USTKTOP) /* old sp */
- PUSHFL /* old flags */
- PUSHL $(UESEL) /* old cs */
- PUSHL $(UTZERO+32) /* old pc */
- MOVL $(UDSEL),AX
- MOVW AX,DS
- MOVW AX,ES
- MOVW AX,GS
- MOVW AX,FS
- IRETL
-
-/*
- * set configuration register
- */
-TEXT config(SB),$0
- MOVL l+0(FP),AX
- MOVL $0x3F3,DX
- OUTB
- OUTB
- RET
diff --git a/src/cmd/8c/cgen.c b/src/cmd/8c/cgen.c
index edb29ad8c..7f02bd96e 100644
--- a/src/cmd/8c/cgen.c
+++ b/src/cmd/8c/cgen.c
@@ -1581,7 +1581,7 @@ sugen(Node *n, Node *nn, int32 w)
nod0.addable = 0;
nod0.right = l;
- /* prtree(&nod0, "hand craft"); /* */
+ // prtree(&nod0, "hand craft");
cgen(&nod0, Z);
}
break;
diff --git a/src/cmd/8g/ggen.c b/src/cmd/8g/ggen.c
index 25adb38c0..6db0474c9 100644
--- a/src/cmd/8g/ggen.c
+++ b/src/cmd/8g/ggen.c
@@ -20,6 +20,32 @@ defframe(Prog *ptxt)
maxstksize = 0;
}
+// Sweep the prog list to mark any used nodes.
+void
+markautoused(Prog* p)
+{
+ for (; p; p = p->link) {
+ if (p->from.type == D_AUTO && p->from.node)
+ p->from.node->used++;
+
+ if (p->to.type == D_AUTO && p->to.node)
+ p->to.node->used++;
+ }
+}
+
+// Fixup instructions after compactframe has moved all autos around.
+void
+fixautoused(Prog* p)
+{
+ for (; p; p = p->link) {
+ if (p->from.type == D_AUTO && p->from.node)
+ p->from.offset += p->from.node->stkdelta;
+
+ if (p->to.type == D_AUTO && p->to.node)
+ p->to.offset += p->to.node->stkdelta;
+ }
+}
+
void
clearfat(Node *nl)
{
@@ -141,15 +167,15 @@ cgen_callinter(Node *n, Node *res, int proc)
nodindreg(&nodsp, types[tptr], D_SP);
nodo.xoffset += widthptr;
- cgen(&nodo, &nodsp); // 0(SP) = 8(REG) -- i.s
+ cgen(&nodo, &nodsp); // 0(SP) = 4(REG) -- i.data
nodo.xoffset -= widthptr;
- cgen(&nodo, &nodr); // REG = 0(REG) -- i.m
+ cgen(&nodo, &nodr); // REG = 0(REG) -- i.tab
if(n->left->xoffset == BADWIDTH)
fatal("cgen_callinter: badwidth");
nodo.xoffset = n->left->xoffset + 3*widthptr + 8;
- cgen(&nodo, &nodr); // REG = 32+offset(REG) -- i.m->fun[f]
+ cgen(&nodo, &nodr); // REG = 20+offset(REG) -- i.tab->fun[f]
// BOTCH nodr.type = fntype;
nodr.type = n->left->type;
diff --git a/src/cmd/8g/gobj.c b/src/cmd/8g/gobj.c
index bc1dfe8bf..31c42a3f2 100644
--- a/src/cmd/8g/gobj.c
+++ b/src/cmd/8g/gobj.c
@@ -226,6 +226,8 @@ dumpfuncs(void)
// fix up pc
pcloc = 0;
for(pl=plist; pl!=nil; pl=pl->link) {
+ if(isblank(pl->name))
+ continue;
for(p=pl->firstpc; p!=P; p=p->link) {
p->loc = pcloc;
if(p->as != ADATA && p->as != AGLOBL)
@@ -235,6 +237,8 @@ dumpfuncs(void)
// put out functions
for(pl=plist; pl!=nil; pl=pl->link) {
+ if(isblank(pl->name))
+ continue;
if(debug['S']) {
s = S;
diff --git a/src/cmd/8g/gsubr.c b/src/cmd/8g/gsubr.c
index 6bcc3eed8..a35c81eb1 100644
--- a/src/cmd/8g/gsubr.c
+++ b/src/cmd/8g/gsubr.c
@@ -100,6 +100,19 @@ patch(Prog *p, Prog *to)
p->to.offset = to->loc;
}
+Prog*
+unpatch(Prog *p)
+{
+ Prog *q;
+
+ if(p->to.type != D_BRANCH)
+ fatal("unpatch: not a branch");
+ q = p->to.branch;
+ p->to.branch = P;
+ p->to.offset = 0;
+ return q;
+}
+
/*
* start a new Prog list.
*/
@@ -123,6 +136,44 @@ newplist(void)
}
void
+clearstk(void)
+{
+ Plist *pl;
+ Prog *p1, *p2;
+ Node sp, di, cx, con, ax;
+
+ if(plast->firstpc->to.offset <= 0)
+ return;
+
+ // reestablish context for inserting code
+ // at beginning of function.
+ pl = plast;
+ p1 = pl->firstpc;
+ p2 = p1->link;
+ pc = mal(sizeof(*pc));
+ clearp(pc);
+ p1->link = pc;
+
+ // zero stack frame
+ nodreg(&sp, types[tptr], D_SP);
+ nodreg(&di, types[tptr], D_DI);
+ nodreg(&cx, types[TUINT32], D_CX);
+ nodconst(&con, types[TUINT32], p1->to.offset / widthptr);
+ gins(ACLD, N, N);
+ gins(AMOVL, &sp, &di);
+ gins(AMOVL, &con, &cx);
+ nodconst(&con, types[TUINT32], 0);
+ nodreg(&ax, types[TUINT32], D_AX);
+ gins(AMOVL, &con, &ax);
+ gins(AREP, N, N);
+ gins(ASTOSL, N, N);
+
+ // continue with original code.
+ gins(ANOP, N, N)->link = p2;
+ pc = P;
+}
+
+void
gused(Node *n)
{
gins(ANOP, n, N); // used
diff --git a/src/cmd/8g/reg.c b/src/cmd/8g/reg.c
index a2f3def37..a4828c3a3 100644
--- a/src/cmd/8g/reg.c
+++ b/src/cmd/8g/reg.c
@@ -1533,6 +1533,7 @@ noreturn(Prog *p)
symlist[1] = pkglookup("panicslice", runtimepkg);
symlist[2] = pkglookup("throwinit", runtimepkg);
symlist[3] = pkglookup("panic", runtimepkg);
+ symlist[4] = pkglookup("panicwrap", runtimepkg);
}
s = p->to.sym;
diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c
index cb900d28d..a9a720af1 100644
--- a/src/cmd/8l/asm.c
+++ b/src/cmd/8l/asm.c
@@ -920,10 +920,6 @@ asmb(void)
break;
Elfput:
- /* elf 386 */
- if(HEADTYPE == Htiny)
- debug['d'] = 1;
-
eh = getElfEhdr();
startva = INITTEXT - HEADR;
@@ -1276,6 +1272,6 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
put(nil, a->asym->name, 'p', a->aoffset, 0, 0, a->gotype);
}
if(debug['v'] || debug['n'])
- Bprint(&bso, "symsize = %uld\n", symsize);
+ Bprint(&bso, "symsize = %d\n", symsize);
Bflush(&bso);
}
diff --git a/src/cmd/8l/list.c b/src/cmd/8l/list.c
index 4e199d767..31ae02346 100644
--- a/src/cmd/8l/list.c
+++ b/src/cmd/8l/list.c
@@ -176,7 +176,7 @@ Dconv(Fmt *fp)
}
brk:
if(a->index != D_NONE) {
- sprint(s, "(%R*%d)", a->index, a->scale);
+ sprint(s, "(%R*%d)", (int)a->index, a->scale);
strcat(str, s);
}
conv:
diff --git a/src/cmd/8l/obj.c b/src/cmd/8l/obj.c
index 440dcb77f..ce7b59518 100644
--- a/src/cmd/8l/obj.c
+++ b/src/cmd/8l/obj.c
@@ -54,11 +54,9 @@ Header headers[] = {
"msdosexe", Hmsdosexe,
"darwin", Hdarwin,
"linux", Hlinux,
- "nacl", Hnacl,
"freebsd", Hfreebsd,
"windows", Hwindows,
"windowsgui", Hwindows,
- "tiny", Htiny,
0, 0
};
@@ -70,10 +68,8 @@ Header headers[] = {
* -Hmsdosexe -Tx -Rx is fake MS-DOS .EXE
* -Hdarwin -Tx -Rx is Apple Mach-O
* -Hlinux -Tx -Rx is Linux ELF32
- * -Hnacl -Tx -Rx was Google Native Client
* -Hfreebsd -Tx -Rx is FreeBSD ELF32
* -Hwindows -Tx -Rx is MS Windows PE32
- * -Htiny -Tx -Rx is tiny (os image)
*/
void
@@ -254,17 +250,6 @@ main(int argc, char *argv[])
if(INITRND == -1)
INITRND = PESECTALIGN;
break;
- case Htiny:
- tlsoffset = 0;
- elfinit();
- HEADR = ELFRESERVE;
- if(INITTEXT == -1)
- INITTEXT = 0x100000+HEADR;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = 4096;
- break;
}
if(INITDAT != 0 && INITRND != 0)
print("warning: -D0x%ux is ignored because of -R0x%ux\n",
@@ -488,7 +473,6 @@ loop:
s = lookup(x, r);
if(x != name)
free(x);
- name = nil;
if(debug['S'] && r == 0)
sig = 1729;
@@ -718,7 +702,6 @@ loop:
lastp = p;
goto loop;
}
- goto loop;
eof:
diag("truncated object file: %s", pn);
diff --git a/src/cmd/8l/pass.c b/src/cmd/8l/pass.c
index 72ae043d6..2e0990c5a 100644
--- a/src/cmd/8l/pass.c
+++ b/src/cmd/8l/pass.c
@@ -414,7 +414,6 @@ dostkoff(void)
autoffset = 0;
q = P;
- q1 = P;
if(pmorestack != P)
if(!(p->from.scale & NOSPLIT)) {
p = appendp(p); // load g into CX
diff --git a/src/cmd/8l/span.c b/src/cmd/8l/span.c
index 66a843b23..a4cba1257 100644
--- a/src/cmd/8l/span.c
+++ b/src/cmd/8l/span.c
@@ -89,7 +89,7 @@ span1(Sym *s)
*bp++ = v;
*bp++ = v>>8;
*bp++ = v>>16;
- *bp++ = v>>24;
+ *bp = v>>24;
}
}
p->comefrom = P;
@@ -1319,7 +1319,7 @@ asmins(Prog *p)
andptr = and;
doasm(p);
if(andptr > and+sizeof and) {
- print("and[] is too short - %d byte instruction\n", andptr - and);
+ print("and[] is too short - %ld byte instruction\n", andptr - and);
errorexit();
}
}
diff --git a/src/cmd/cc/dcl.c b/src/cmd/cc/dcl.c
index d7604b649..6f1b8a9a9 100644
--- a/src/cmd/cc/dcl.c
+++ b/src/cmd/cc/dcl.c
@@ -1378,7 +1378,6 @@ tmerge(Type *t1, Sym *s)
Type *ta, *tb, *t2;
t2 = s->type;
-/*print("merge %T; %T\n", t1, t2);/**/
for(;;) {
if(t1 == T || t2 == T || t1 == t2)
break;
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index 10411e94f..6b930f151 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -13,6 +13,7 @@ import (
"debug/elf"
"debug/macho"
"debug/pe"
+ "encoding/binary"
"flag"
"fmt"
"go/ast"
@@ -229,9 +230,9 @@ func splitQuoted(s string) (r []string, err os.Error) {
args = append(args, string(arg[:i]))
}
if quote != 0 {
- err = os.ErrorString("unclosed quote")
+ err = os.NewError("unclosed quote")
} else if escaped {
- err = os.ErrorString("unfinished escaping")
+ err = os.NewError("unfinished escaping")
}
return args, err
}
@@ -477,7 +478,27 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
fmt.Fprintf(&b, "enum { __cgo_enum__%d = %s };\n", i, n.C)
}
}
- d := p.gccDebug(b.Bytes())
+
+ // Apple's LLVM-based gcc does not include the enumeration
+ // names and values in its DWARF debug output. In case we're
+ // using such a gcc, create a data block initialized with the values.
+ // We can read them out of the object file.
+ fmt.Fprintf(&b, "long long __cgodebug_data[] = {\n")
+ for _, n := range names {
+ if n.Kind == "const" {
+ fmt.Fprintf(&b, "\t%s,\n", n.C)
+ } else {
+ fmt.Fprintf(&b, "\t0,\n")
+ }
+ }
+ fmt.Fprintf(&b, "\t0\n")
+ fmt.Fprintf(&b, "};\n")
+
+ d, bo, debugData := p.gccDebug(b.Bytes())
+ enumVal := make([]int64, len(debugData)/8)
+ for i := range enumVal {
+ enumVal[i] = int64(bo.Uint64(debugData[i*8:]))
+ }
// Scan DWARF info for top-level TagVariable entries with AttrName __cgo__i.
types := make([]dwarf.Type, len(names))
@@ -569,9 +590,12 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
// Remove injected enum to ensure the value will deep-compare
// equally in future loads of the same constant.
n.Type.EnumValues[k] = 0, false
+ } else if n.Kind == "const" && i < len(enumVal) {
+ n.Const = strconv.Itoa64(enumVal[i])
}
}
}
+
}
// rewriteRef rewrites all the C.xxx references in f.AST to refer to the
@@ -593,6 +617,9 @@ func (p *Package) rewriteRef(f *File) {
// are trying to do a ,err call. Also check that
// functions are only used in calls.
for _, r := range f.Ref {
+ if r.Name.Kind == "const" && r.Name.Const == "" {
+ error(r.Pos(), "unable to find value of constant C.%s", r.Name.Go)
+ }
var expr ast.Expr = ast.NewIdent(r.Name.Mangle) // default
switch r.Context {
case "call", "call2":
@@ -670,7 +697,7 @@ func (p *Package) gccMachine() []string {
return nil
}
-const gccTmp = "_obj/_cgo_.o"
+var gccTmp = objDir + "_cgo_.o"
// gccCmd returns the gcc command line to use for compiling
// the input.
@@ -692,29 +719,57 @@ func (p *Package) gccCmd() []string {
}
// gccDebug runs gcc -gdwarf-2 over the C program stdin and
-// returns the corresponding DWARF data and any messages
-// printed to standard error.
-func (p *Package) gccDebug(stdin []byte) *dwarf.Data {
+// returns the corresponding DWARF data and, if present, debug data block.
+func (p *Package) gccDebug(stdin []byte) (*dwarf.Data, binary.ByteOrder, []byte) {
runGcc(stdin, p.gccCmd())
- // Try to parse f as ELF and Mach-O and hope one works.
- var f interface {
- DWARF() (*dwarf.Data, os.Error)
- }
- var err os.Error
- if f, err = elf.Open(gccTmp); err != nil {
- if f, err = macho.Open(gccTmp); err != nil {
- if f, err = pe.Open(gccTmp); err != nil {
- fatalf("cannot parse gcc output %s as ELF or Mach-O or PE object", gccTmp)
+ if f, err := macho.Open(gccTmp); err == nil {
+ d, err := f.DWARF()
+ if err != nil {
+ fatalf("cannot load DWARF output from %s: %v", gccTmp, err)
+ }
+ var data []byte
+ if f.Symtab != nil {
+ for i := range f.Symtab.Syms {
+ s := &f.Symtab.Syms[i]
+ // Mach-O still uses a leading _ to denote non-assembly symbols.
+ if s.Name == "_"+"__cgodebug_data" {
+ // Found it. Now find data section.
+ if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) {
+ sect := f.Sections[i]
+ if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
+ if sdat, err := sect.Data(); err == nil {
+ data = sdat[s.Value-sect.Addr:]
+ }
+ }
+ }
+ }
}
}
+ return d, f.ByteOrder, data
}
- d, err := f.DWARF()
- if err != nil {
- fatalf("cannot load DWARF debug information from %s: %s", gccTmp, err)
+ // Can skip debug data block in ELF and PE for now.
+ // The DWARF information is complete.
+
+ if f, err := elf.Open(gccTmp); err == nil {
+ d, err := f.DWARF()
+ if err != nil {
+ fatalf("cannot load DWARF output from %s: %v", gccTmp, err)
+ }
+ return d, f.ByteOrder, nil
}
- return d
+
+ if f, err := pe.Open(gccTmp); err == nil {
+ d, err := f.DWARF()
+ if err != nil {
+ fatalf("cannot load DWARF output from %s: %v", gccTmp, err)
+ }
+ return d, binary.LittleEndian, nil
+ }
+
+ fatalf("cannot parse gcc output %s as ELF, Mach-O, PE object", gccTmp)
+ panic("not reached")
}
// gccDefines runs gcc -E -dM -xc - over the C program stdin
diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go
index 84aeccc21..be9c2bc4f 100644
--- a/src/cmd/cgo/main.go
+++ b/src/cmd/cgo/main.go
@@ -18,6 +18,7 @@ import (
"go/token"
"io"
"os"
+ "path/filepath"
"reflect"
"strings"
)
@@ -228,7 +229,7 @@ func main() {
}
pkg := f.Package
if dir := os.Getenv("CGOPKGPATH"); dir != "" {
- pkg = dir + "/" + pkg
+ pkg = filepath.Join(dir, pkg)
}
p.PackagePath = pkg
p.writeOutput(f, input)
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index dbc7bcf69..7eecb3437 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -14,17 +14,20 @@ import (
"go/printer"
"go/token"
"os"
+ "path/filepath"
"strings"
)
+var objDir = "_obj" + string(filepath.Separator)
+
// writeDefs creates output files to be compiled by 6g, 6c, and gcc.
// (The comments here say 6g and 6c but the code applies to the 8 and 5 tools too.)
func (p *Package) writeDefs() {
- fgo2 := creat("_obj/_cgo_gotypes.go")
- fc := creat("_obj/_cgo_defun.c")
- fm := creat("_obj/_cgo_main.c")
+ fgo2 := creat(objDir + "_cgo_gotypes.go")
+ fc := creat(objDir + "_cgo_defun.c")
+ fm := creat(objDir + "_cgo_main.c")
- fflg := creat("_obj/_cgo_flags")
+ fflg := creat(objDir + "_cgo_flags")
for k, v := range p.CgoFlags {
fmt.Fprintf(fflg, "_CGO_%s=%s\n", k, v)
}
@@ -285,8 +288,8 @@ func (p *Package) writeOutput(f *File, srcfile string) {
base = base[0 : len(base)-3]
}
base = strings.Map(slashToUnderscore, base)
- fgo1 := creat("_obj/" + base + ".cgo1.go")
- fgcc := creat("_obj/" + base + ".cgo2.c")
+ fgo1 := creat(objDir + base + ".cgo1.go")
+ fgcc := creat(objDir + base + ".cgo2.c")
p.GoFiles = append(p.GoFiles, base+".cgo1.go")
p.GccFiles = append(p.GccFiles, base+".cgo2.c")
@@ -361,7 +364,7 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
// Write out the various stubs we need to support functions exported
// from Go so that they are callable from C.
func (p *Package) writeExports(fgo2, fc, fm *os.File) {
- fgcc := creat("_obj/_cgo_export.c")
+ fgcc := creat(objDir + "_cgo_export.c")
fgcch := creat("_cgo_export.h")
fmt.Fprintf(fgcch, "/* Created by cgo - DO NOT EDIT. */\n")
diff --git a/src/cmd/cgo/util.go b/src/cmd/cgo/util.go
index 1ca24103e..e79b0e1bf 100644
--- a/src/cmd/cgo/util.go
+++ b/src/cmd/cgo/util.go
@@ -103,7 +103,7 @@ func creat(name string) *os.File {
}
func slashToUnderscore(c int) int {
- if c == '/' {
+ if c == '/' || c == '\\' || c == ':' {
c = '_'
}
return c
diff --git a/src/cmd/cov/Makefile b/src/cmd/cov/Makefile
index fdeb14636..95dba9c60 100644
--- a/src/cmd/cov/Makefile
+++ b/src/cmd/cov/Makefile
@@ -17,9 +17,6 @@ OFILES=\
HFILES=\
tree.h\
-LIB=\
- ../../../lib/libmach.a\
-
NOINSTALL=1
include ../../Make.ccmd
diff --git a/src/cmd/gc/builtin.c.boot b/src/cmd/gc/builtin.c.boot
index c9bf501d1..95098c8af 100644
--- a/src/cmd/gc/builtin.c.boot
+++ b/src/cmd/gc/builtin.c.boot
@@ -6,6 +6,7 @@ char *runtimeimport =
"func \"\".panicslice ()\n"
"func \"\".throwreturn ()\n"
"func \"\".throwinit ()\n"
+ "func \"\".panicwrap (? string, ? string, ? string)\n"
"func \"\".panic (? interface { })\n"
"func \"\".recover (? *int32) interface { }\n"
"func \"\".printbool (? bool)\n"
@@ -22,6 +23,7 @@ char *runtimeimport =
"func \"\".printsp ()\n"
"func \"\".goprintf ()\n"
"func \"\".concatstring ()\n"
+ "func \"\".append ()\n"
"func \"\".appendslice (typ *uint8, x any, y []any) any\n"
"func \"\".cmpstring (? string, ? string) int\n"
"func \"\".slicestring (? string, ? int, ? int) string\n"
@@ -81,7 +83,7 @@ char *runtimeimport =
"func \"\".selectgo (sel *uint8)\n"
"func \"\".block ()\n"
"func \"\".makeslice (typ *uint8, nel int64, cap int64) []any\n"
- "func \"\".growslice (typ *uint8, old []any, cap int64) []any\n"
+ "func \"\".growslice (typ *uint8, old []any, n int64) []any\n"
"func \"\".sliceslice1 (old []any, lb uint64, width uint64) []any\n"
"func \"\".sliceslice (old []any, lb uint64, hb uint64, width uint64) []any\n"
"func \"\".slicearray (old *any, nel uint64, lb uint64, hb uint64, width uint64) []any\n"
@@ -101,9 +103,9 @@ char *unsafeimport =
"package unsafe\n"
"import runtime \"runtime\"\n"
"type \"\".Pointer uintptr\n"
- "func \"\".Offsetof (? any) int\n"
- "func \"\".Sizeof (? any) int\n"
- "func \"\".Alignof (? any) int\n"
+ "func \"\".Offsetof (? any) uintptr\n"
+ "func \"\".Sizeof (? any) uintptr\n"
+ "func \"\".Alignof (? any) uintptr\n"
"func \"\".Typeof (i interface { }) interface { }\n"
"func \"\".Reflect (i interface { }) (typ interface { }, addr \"\".Pointer)\n"
"func \"\".Unreflect (typ interface { }, addr \"\".Pointer) interface { }\n"
diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c
index 83be82f92..7290f9d3b 100644
--- a/src/cmd/gc/dcl.c
+++ b/src/cmd/gc/dcl.c
@@ -39,6 +39,7 @@ push(void)
Sym *d;
d = mal(sizeof(*d));
+ d->lastlineno = lineno;
d->link = dclstack;
dclstack = d;
return d;
@@ -60,6 +61,7 @@ void
popdcl(void)
{
Sym *d, *s;
+ int lno;
// if(dflag())
// print("revert\n");
@@ -68,7 +70,9 @@ popdcl(void)
if(d->name == nil)
break;
s = pkglookup(d->name, d->pkg);
+ lno = s->lastlineno;
dcopy(s, d);
+ d->lastlineno = lno;
if(dflag())
print("\t%L pop %S %p\n", lineno, s, s->def);
}
@@ -81,19 +85,12 @@ popdcl(void)
void
poptodcl(void)
{
- Sym *d, *s;
-
- for(d=dclstack; d!=S; d=d->link) {
- if(d->name == nil)
- break;
- s = pkglookup(d->name, d->pkg);
- dcopy(s, d);
- if(dflag())
- print("\t%L pop %S\n", lineno, s);
- }
- if(d == S)
- fatal("poptodcl: no mark");
- dclstack = d;
+ // pop the old marker and push a new one
+ // (cannot reuse the existing one)
+ // because we use the markers to identify blocks
+ // for the goto restriction checks.
+ popdcl();
+ markdcl();
}
void
@@ -1247,3 +1244,5 @@ funccompile(Node *n, int isclosure)
dclcontext = PEXTERN;
}
+
+
diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c
index feb55e905..cb66921ba 100644
--- a/src/cmd/gc/gen.c
+++ b/src/cmd/gc/gen.c
@@ -11,6 +11,10 @@
static void cgen_dcl(Node *n);
static void cgen_proc(Node *n, int proc);
+static void checkgoto(Node*, Node*);
+
+static Label *labellist;
+static Label *lastlabel;
Node*
sysfunc(char *name)
@@ -80,71 +84,122 @@ clearlabels(void)
lastlabel = L;
}
-static void
-newlab(int op, Node *nlab, Node *stmt)
+static Label*
+newlab(Node *n)
{
- Label *lab;
Sym *s;
- int32 lno;
+ Label *lab;
+
+ s = n->left->sym;
+ if((lab = s->label) == L) {
+ lab = mal(sizeof(*lab));
+ if(lastlabel == nil)
+ labellist = lab;
+ else
+ lastlabel->link = lab;
+ lastlabel = lab;
+ lab->sym = s;
+ s->label = lab;
+ }
- s = nlab->left->sym;
- lno = nlab->left->lineno;
-
- lab = mal(sizeof(*lab));
- if(lastlabel == nil)
- labellist = lab;
- else
- lastlabel->link = lab;
- lastlabel = lab;
-
- lab->lineno = lno;
- lab->sym = s;
- lab->op = op;
- lab->label = pc;
- lab->stmt = stmt;
- if(op == OLABEL) {
- if(s->label != L) {
- lineno = lno;
- yyerror("label %S already defined at %L", s, s->label->lineno);
- } else
- s->label = lab;
- }
+ if(n->op == OLABEL) {
+ if(lab->def != N)
+ yyerror("label %S already defined at %L", s, lab->def->lineno);
+ else
+ lab->def = n;
+ } else
+ lab->use = list(lab->use, n);
+
+ return lab;
}
void
checklabels(void)
{
- Label *l;
- Sym *s;
- int lno;
+ Label *lab;
+ NodeList *l;
- lno = lineno;
-
- // resolve goto using syms
- for(l=labellist; l!=L; l=l->link) {
- switch(l->op) {
- case OGOTO:
- s = l->sym;
- if(s->label == L) {
- lineno = l->lineno;
- yyerror("label %S not defined", s);
- break;
- }
- s->label->used = 1;
- patch(l->label, s->label->label);
- break;
+ for(lab=labellist; lab!=L; lab=lab->link) {
+ if(lab->def == N) {
+ for(l=lab->use; l; l=l->next)
+ yyerrorl(l->n->lineno, "label %S not defined", lab->sym);
+ continue;
}
+ if(lab->use == nil && !lab->used) {
+ yyerrorl(lab->def->lineno, "label %S defined and not used", lab->sym);
+ continue;
+ }
+ if(lab->gotopc != P)
+ fatal("label %S never resolved", lab->sym);
+ for(l=lab->use; l; l=l->next)
+ checkgoto(l->n, lab->def);
}
-
- // diagnose unused labels
- for(l=labellist; l!=L; l=l->link) {
- if(l->op == OLABEL && !l->used) {
- lineno = l->lineno;
- yyerror("label %S defined and not used", l->sym);
+}
+
+static void
+checkgoto(Node *from, Node *to)
+{
+ int nf, nt;
+ Sym *block, *dcl, *fs, *ts;
+ int lno;
+
+ if(from->sym == to->sym)
+ return;
+
+ nf = 0;
+ for(fs=from->sym; fs; fs=fs->link)
+ nf++;
+ nt = 0;
+ for(fs=to->sym; fs; fs=fs->link)
+ nt++;
+ fs = from->sym;
+ for(; nf > nt; nf--)
+ fs = fs->link;
+ if(fs != to->sym) {
+ lno = lineno;
+ setlineno(from);
+
+ // decide what to complain about.
+ // prefer to complain about 'into block' over declarations,
+ // so scan backward to find most recent block or else dcl.
+ block = S;
+ dcl = S;
+ ts = to->sym;
+ for(; nt > nf; nt--) {
+ if(ts->pkg == nil)
+ block = ts;
+ else
+ dcl = ts;
+ ts = ts->link;
}
+ while(ts != fs) {
+ if(ts->pkg == nil)
+ block = ts;
+ else
+ dcl = ts;
+ ts = ts->link;
+ fs = fs->link;
+ }
+
+ if(block)
+ yyerror("goto %S jumps into block starting at %L", from->left->sym, block->lastlineno);
+ else
+ yyerror("goto %S jumps over declaration of %S at %L", from->left->sym, dcl, dcl->lastlineno);
+ lineno = lno;
}
-
- lineno = lno;
+}
+
+static Label*
+stmtlabel(Node *n)
+{
+ Label *lab;
+
+ if(n->sym != S)
+ if((lab = n->sym->label) != L)
+ if(lab->def != N)
+ if(lab->def->right == n)
+ return lab;
+ return L;
}
/*
@@ -193,11 +248,6 @@ gen(Node *n)
break;
case OEMPTY:
- // insert no-op so that
- // L:; for { }
- // does not treat L as a label for the loop.
- if(lastlabel != L && lastlabel->label == p3)
- gused(N);
break;
case OBLOCK:
@@ -205,12 +255,41 @@ gen(Node *n)
break;
case OLABEL:
- newlab(OLABEL, n, n->right);
+ lab = newlab(n);
+
+ // if there are pending gotos, resolve them all to the current pc.
+ for(p1=lab->gotopc; p1; p1=p2) {
+ p2 = unpatch(p1);
+ patch(p1, pc);
+ }
+ lab->gotopc = P;
+ if(lab->labelpc == P)
+ lab->labelpc = pc;
+
+ if(n->right) {
+ switch(n->right->op) {
+ case OFOR:
+ case OSWITCH:
+ case OSELECT:
+ // so stmtlabel can find the label
+ n->right->sym = lab->sym;
+ }
+ }
break;
case OGOTO:
- newlab(OGOTO, n, N);
- gjmp(P);
+ // if label is defined, emit jump to it.
+ // otherwise save list of pending gotos in lab->gotopc.
+ // the list is linked through the normal jump target field
+ // to avoid a second list. (the jumps are actually still
+ // valid code, since they're just going to another goto
+ // to the same label. we'll unwind it when we learn the pc
+ // of the label in the OLABEL case above.)
+ lab = newlab(n);
+ if(lab->labelpc != P)
+ gjmp(lab->labelpc);
+ else
+ lab->gotopc = gjmp(lab->gotopc);
break;
case OBREAK:
@@ -265,12 +344,10 @@ gen(Node *n)
continpc = pc;
// define break and continue labels
- if((lab = lastlabel) != L && lab->label == p3 && lab->op == OLABEL && lab->stmt == n) {
+ if((lab = stmtlabel(n)) != L) {
lab->breakpc = breakpc;
lab->continpc = continpc;
- } else
- lab = L;
-
+ }
gen(n->nincr); // contin: incr
patch(p1, pc); // test:
bgen(n->ntest, 0, breakpc); // if(!test) goto break
@@ -303,10 +380,8 @@ gen(Node *n)
breakpc = gjmp(P); // break: goto done
// define break label
- if((lab = lastlabel) != L && lab->label == p3 && lab->op == OLABEL && lab->stmt == n)
+ if((lab = stmtlabel(n)) != L)
lab->breakpc = breakpc;
- else
- lab = L;
patch(p1, pc); // test:
genlist(n->nbody); // switch(test) body
@@ -322,10 +397,8 @@ gen(Node *n)
breakpc = gjmp(P); // break: goto done
// define break label
- if((lab = lastlabel) != L && lab->label == p3 && lab->op == OLABEL && lab->stmt == n)
+ if((lab = stmtlabel(n)) != L)
lab->breakpc = breakpc;
- else
- lab = L;
patch(p1, pc); // test:
genlist(n->nbody); // select() body
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index 86db48391..b68768165 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -278,6 +278,7 @@ struct Node
int32 iota;
};
#define N ((Node*)0)
+EXTERN int32 walkgen;
struct NodeList
{
@@ -632,21 +633,20 @@ typedef struct Prog Prog;
struct Label
{
- uchar op; // OGOTO/OLABEL
uchar used;
Sym* sym;
- Node* stmt;
- Prog* label; // pointer to code
+ Node* def;
+ NodeList* use;
+ Label* link;
+
+ // for use during gen
+ Prog* gotopc; // pointer to unresolved gotos
+ Prog* labelpc; // pointer to code
Prog* breakpc; // pointer to code
Prog* continpc; // pointer to code
- Label* link;
- int32 lineno;
};
#define L ((Label*)0)
-EXTERN Label* labellist;
-EXTERN Label* lastlabel;
-
/*
* note this is the runtime representation
* of the compilers arrays.
@@ -691,6 +691,7 @@ EXTERN char* infile;
EXTERN char* outfile;
EXTERN Biobuf* bout;
EXTERN int nerrors;
+EXTERN int nsavederrors;
EXTERN int nsyntaxerrors;
EXTERN int safemode;
EXTERN char namebuf[NSYMB];
@@ -913,8 +914,8 @@ Type* pkgtype(Sym *s);
void allocparams(void);
void cgen_as(Node *nl, Node *nr);
void cgen_callmeth(Node *n, int proc);
-void checklabels(void);
void clearlabels(void);
+void checklabels(void);
int dotoffset(Node *n, int *oary, Node **nn);
void gen(Node *n);
void genlist(NodeList *l);
@@ -1132,6 +1133,7 @@ Type* ptrto(Type *t);
void* remal(void *p, int32 on, int32 n);
Sym* restrictlookup(char *name, Pkg *pkg);
Node* safeexpr(Node *n, NodeList **init);
+void saveerrors(void);
Node* cheapexpr(Node *n, NodeList **init);
int32 setlineno(Node *n);
void setmaxarg(Type *t);
@@ -1195,7 +1197,7 @@ void walkstmt(Node **np);
void walkstmtlist(NodeList *l);
/*
- * arch-specific ggen.c/gsubr.c/gobj.c
+ * arch-specific ggen.c/gsubr.c/gobj.c/pgen.c
*/
#define P ((Prog*)0)
@@ -1237,6 +1239,7 @@ int dsymptr(Sym *s, int off, Sym *x, int xoff);
int duintxx(Sym *s, int off, uint64 v, int wid);
void dumpdata(void);
void dumpfuncs(void);
+void fixautoused(Prog*);
void gdata(Node*, Node*, int);
void gdatacomplex(Node*, Mpcplx*);
void gdatastring(Node*, Strlit*);
@@ -1246,12 +1249,15 @@ void ggloblsym(Sym *s, int32 width, int dupok);
Prog* gjmp(Prog*);
void gused(Node*);
int isfat(Type*);
+void markautoused(Prog*);
Plist* newplist(void);
Node* nodarg(Type*, int);
void nopout(Prog*);
void patch(Prog*, Prog*);
+Prog* unpatch(Prog*);
void zfile(Biobuf *b, char *p, int n);
void zhist(Biobuf *b, int line, vlong offset);
void zname(Biobuf *b, Sym *s, int t);
void data(void);
void text(void);
+
diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y
index 1278c2586..5d28c0e3b 100644
--- a/src/cmd/gc/go.y
+++ b/src/cmd/gc/go.y
@@ -66,7 +66,7 @@ static void fixlbrace(int);
%type <node> switch_stmt uexpr
%type <node> xfndcl typedcl
-%type <list> xdcl fnbody fnres switch_body loop_body dcl_name_list
+%type <list> xdcl fnbody fnres loop_body dcl_name_list
%type <list> new_name_list expr_list keyval_list braced_keyval_list expr_or_type_list xdcl_list
%type <list> oexpr_list caseblock_list stmt_list oarg_type_list_ocomma arg_type_list
%type <list> interfacedcl_list vardcl vardcl_list structdcl structdcl_list
@@ -449,7 +449,7 @@ case:
// will be converted to OCASE
// right will point to next case
// done in casebody()
- poptodcl();
+ markdcl();
$$ = nod(OXCASE, N, N);
$$->list = $2;
if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) {
@@ -468,7 +468,7 @@ case:
// will be converted to OCASE
// right will point to next case
// done in casebody()
- poptodcl();
+ markdcl();
$$ = nod(OXCASE, N, N);
if($2->next == nil)
n = nod(OAS, $2->n, $4);
@@ -484,7 +484,7 @@ case:
// will be converted to OCASE
// right will point to next case
// done in casebody()
- poptodcl();
+ markdcl();
$$ = nod(OXCASE, N, N);
$$->list = list1(colas($2, list1($4)));
}
@@ -492,7 +492,7 @@ case:
{
Node *n;
- poptodcl();
+ markdcl();
$$ = nod(OXCASE, N, N);
if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) {
// type switch - declare variable
@@ -514,17 +514,6 @@ compound_stmt:
popdcl();
}
-switch_body:
- LBODY
- {
- markdcl();
- }
- caseblock_list '}'
- {
- $$ = $3;
- popdcl();
- }
-
caseblock:
case
{
@@ -553,6 +542,7 @@ caseblock:
yyerror("missing statement after label");
$$ = $1;
$$->nbody = $3;
+ popdcl();
}
caseblock_list:
@@ -674,11 +664,11 @@ switch_stmt:
n = N;
typesw = nod(OXXX, typesw, n);
}
- switch_body
+ LBODY caseblock_list '}'
{
$$ = $3;
$$->op = OSWITCH;
- $$->list = $5;
+ $$->list = $6;
typesw = typesw->left;
popdcl();
}
@@ -686,15 +676,13 @@ switch_stmt:
select_stmt:
LSELECT
{
- markdcl();
typesw = nod(OXXX, typesw, N);
}
- switch_body
+ LBODY caseblock_list '}'
{
$$ = nod(OSELECT, N, N);
- $$->list = $3;
+ $$->list = $4;
typesw = typesw->left;
- popdcl();
}
/*
@@ -1474,13 +1462,19 @@ non_dcl_stmt:
$$ = $1;
$$->nelse = list1($3);
}
-| labelname ':' stmt
+| labelname ':'
+ {
+ $1 = nod(OLABEL, $1, N);
+ $1->sym = dclstack; // context, for goto restrictions
+ }
+ stmt
{
NodeList *l;
- l = list1(nod(OLABEL, $1, $3));
- if($3)
- l = list(l, $3);
+ $1->right = $4;
+ l = list1($1);
+ if($4)
+ l = list(l, $4);
$$ = liststmt(l);
}
| LFALL
@@ -1507,6 +1501,7 @@ non_dcl_stmt:
| LGOTO new_name
{
$$ = nod(OGOTO, $2, N);
+ $$->sym = dclstack; // context, for goto restrictions
}
| LRETURN oexpr_list
{
diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
index 88acb60af..5c642375a 100644
--- a/src/cmd/gc/lex.c
+++ b/src/cmd/gc/lex.c
@@ -97,7 +97,7 @@ fault(int s)
// in the program, don't bother complaining
// about the seg fault too; let the user clean up
// the code and try again.
- if(nerrors > 0)
+ if(nsavederrors + nerrors > 0)
errorexit();
fatal("fault");
}
@@ -256,7 +256,10 @@ main(int argc, char *argv[])
for(l=xtop; l; l=l->next)
if(l->n->op == ODCLFUNC) {
curfn = l->n;
+ saveerrors();
typechecklist(l->n->nbody, Etop);
+ if(nerrors != 0)
+ l->n->nbody = nil; // type errors; do not compile
}
curfn = nil;
@@ -264,7 +267,7 @@ main(int argc, char *argv[])
if(l->n->op == ODCLFUNC)
funccompile(l->n, 0);
- if(nerrors == 0)
+ if(nsavederrors+nerrors == 0)
fninit(xtop);
while(closures) {
@@ -278,12 +281,12 @@ main(int argc, char *argv[])
if(l->n->op == ONAME)
typecheck(&l->n, Erv);
- if(nerrors)
+ if(nerrors+nsavederrors)
errorexit();
dumpobj();
- if(nerrors)
+ if(nerrors+nsavederrors)
errorexit();
flusherrors();
@@ -291,6 +294,13 @@ main(int argc, char *argv[])
return 0;
}
+void
+saveerrors(void)
+{
+ nsavederrors += nerrors;
+ nerrors = 0;
+}
+
static int
arsize(Biobuf *b, char *name)
{
diff --git a/src/cmd/gc/pgen.c b/src/cmd/gc/pgen.c
index ab6186697..552e405d8 100644
--- a/src/cmd/gc/pgen.c
+++ b/src/cmd/gc/pgen.c
@@ -30,6 +30,8 @@ compile(Node *fn)
if(fn->nbody == nil)
return;
+ saveerrors();
+
// set up domain for labels
clearlabels();
@@ -53,7 +55,7 @@ compile(Node *fn)
hasdefer = 0;
walk(curfn);
- if(nerrors != 0 || isblank(curfn->nname))
+ if(nerrors != 0)
goto ret;
allocparams();
@@ -67,7 +69,7 @@ compile(Node *fn)
setlineno(curfn);
nodconst(&nod1, types[TINT32], 0);
- ptxt = gins(ATEXT, curfn->nname, &nod1);
+ ptxt = gins(ATEXT, isblank(curfn->nname) ? N : curfn->nname, &nod1);
afunclit(&ptxt->from);
ginit();
@@ -111,8 +113,7 @@ compile(Node *fn)
}
oldstksize = stksize;
- if(thechar != '5')
- compactframe(ptxt);
+ compactframe(ptxt);
if(0)
print("compactframe: %ld to %ld\n", oldstksize, stksize);
@@ -142,12 +143,12 @@ cmpstackvar(Node *a, Node *b)
}
+// TODO(lvd) find out where the PAUTO/OLITERAL nodes come from.
static void
compactframe(Prog* ptxt)
{
NodeList *ll;
Node* n;
- Prog *p;
uint32 w;
if (stksize == 0)
@@ -155,17 +156,10 @@ compactframe(Prog* ptxt)
// Mark the PAUTO's unused.
for(ll=curfn->dcl; ll != nil; ll=ll->next)
- if (ll->n->class == PAUTO && ll->n->op == ONAME)
+ if (ll->n->class == PAUTO)
ll->n->used = 0;
- // Sweep the prog list to mark any used nodes.
- for (p = ptxt; p; p = p->link) {
- if (p->from.type == D_AUTO && p->from.node)
- p->from.node->used++;
-
- if (p->to.type == D_AUTO && p->to.node)
- p->to.node->used++;
- }
+ markautoused(ptxt);
listsort(&curfn->dcl, cmpstackvar);
@@ -191,7 +185,6 @@ compactframe(Prog* ptxt)
stksize = 0;
for(ll = curfn->dcl; ll != nil; ll=ll->next) {
n = ll->n;
- // TODO find out where the literal autos come from
if (n->class != PAUTO || n->op != ONAME)
continue;
@@ -205,14 +198,7 @@ compactframe(Prog* ptxt)
n->stkdelta = -stksize - n->xoffset;
}
- // Fixup instructions.
- for (p = ptxt; p; p = p->link) {
- if (p->from.type == D_AUTO && p->from.node)
- p->from.offset += p->from.node->stkdelta;
-
- if (p->to.type == D_AUTO && p->to.node)
- p->to.offset += p->to.node->stkdelta;
- }
+ fixautoused(ptxt);
// The debug information needs accurate offsets on the symbols.
for(ll = curfn->dcl ;ll != nil; ll=ll->next) {
diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go
index 00fc720b8..e13c95db9 100644
--- a/src/cmd/gc/runtime.go
+++ b/src/cmd/gc/runtime.go
@@ -15,6 +15,7 @@ func panicindex()
func panicslice()
func throwreturn()
func throwinit()
+func panicwrap(string, string, string)
func panic(interface{})
func recover(*int32) interface{}
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index 49797f9df..8eb60de31 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -3131,8 +3131,9 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
NodeList *l, *args, *in, *out;
Type *tpad;
int isddd;
+ Val v;
- if(0 && debug['r'])
+ if(debug['r'])
print("genwrapper rcvrtype=%T method=%T newnam=%S\n",
rcvr, method, newnam);
@@ -3174,17 +3175,38 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
args = list(args, l->n->left);
isddd = l->n->left->isddd;
}
+
+ // generate nil pointer check for better error
+ if(isptr[rcvr->etype] && rcvr->type == getthisx(method->type)->type->type) {
+ // generating wrapper from *T to T.
+ n = nod(OIF, N, N);
+ n->ntest = nod(OEQ, this->left, nodnil());
+ // these strings are already in the reflect tables,
+ // so no space cost to use them here.
+ l = nil;
+ v.ctype = CTSTR;
+ v.u.sval = strlit(rcvr->type->sym->pkg->name); // package name
+ l = list(l, nodlit(v));
+ v.u.sval = strlit(rcvr->type->sym->name); // type name
+ l = list(l, nodlit(v));
+ v.u.sval = strlit(method->sym->name);
+ l = list(l, nodlit(v)); // method name
+ call = nod(OCALL, syslook("panicwrap", 0), N);
+ call->list = l;
+ n->nbody = list1(call);
+ fn->nbody = list(fn->nbody, n);
+ }
// generate call
call = nod(OCALL, adddot(nod(OXDOT, this->left, newname(method->sym))), N);
call->list = args;
call->isddd = isddd;
- fn->nbody = list1(call);
if(method->type->outtuple > 0) {
n = nod(ORETURN, N, N);
- n->list = fn->nbody;
- fn->nbody = list1(n);
+ n->list = list1(call);
+ call = n;
}
+ fn->nbody = list(fn->nbody, call);
if(0 && debug['r'])
dumplist("genwrapper body", fn->nbody);
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c
index 04dc1a507..dfe0f30f7 100644
--- a/src/cmd/gc/typecheck.c
+++ b/src/cmd/gc/typecheck.c
@@ -2716,6 +2716,11 @@ typecheckdef(Node *n)
default:
fatal("typecheckdef %O", n->op);
+ case OGOTO:
+ case OLABEL:
+ // not really syms
+ break;
+
case OLITERAL:
if(n->ntype != N) {
typecheck(&n->ntype, Etype);
@@ -2772,7 +2777,7 @@ typecheckdef(Node *n)
if(n->defn == N) {
if(n->etype != 0) // like OPRINTN
break;
- if(nerrors > 0) {
+ if(nsavederrors+nerrors > 0) {
// Can have undefined variables in x := foo
// that make x have an n->ndefn == nil.
// If there are other errors anyway, don't
diff --git a/src/cmd/gc/unsafe.c b/src/cmd/gc/unsafe.c
index 540994ddd..d304077c8 100644
--- a/src/cmd/gc/unsafe.c
+++ b/src/cmd/gc/unsafe.c
@@ -92,6 +92,6 @@ ret:
mpmovecfix(val.u.xval, v);
n = nod(OLITERAL, N, N);
n->val = val;
- n->type = types[TINT];
+ n->type = types[TUINTPTR];
return n;
}
diff --git a/src/cmd/gc/unsafe.go b/src/cmd/gc/unsafe.go
index b2a341d39..db27d7425 100644
--- a/src/cmd/gc/unsafe.go
+++ b/src/cmd/gc/unsafe.go
@@ -10,9 +10,11 @@ package PACKAGE
type Pointer uintptr // not really; filled in by compiler
-func Offsetof(any) int
-func Sizeof(any) int
-func Alignof(any) int
+// return types here are ignored; see unsafe.c
+func Offsetof(any) uintptr
+func Sizeof(any) uintptr
+func Alignof(any) uintptr
+
func Typeof(i interface{}) (typ interface{})
func Reflect(i interface{}) (typ interface{}, addr Pointer)
func Unreflect(typ interface{}, addr Pointer) (ret interface{})
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index 65a504bff..4d06179eb 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -243,7 +243,16 @@ walkstmt(Node **np)
break;
case OPROC:
- walkexpr(&n->left, &n->ninit);
+ switch(n->left->op) {
+ case OPRINT:
+ case OPRINTN:
+ walkexprlist(n->left->list, &n->ninit);
+ n->left = walkprint(n->left, &n->ninit, 1);
+ break;
+ default:
+ walkexpr(&n->left, &n->ninit);
+ break;
+ }
break;
case ORETURN:
diff --git a/src/cmd/godefs/Makefile b/src/cmd/godefs/Makefile
index b5c76fb0f..77cd26c04 100644
--- a/src/cmd/godefs/Makefile
+++ b/src/cmd/godefs/Makefile
@@ -14,3 +14,6 @@ OFILES=\
HFILES=a.h
include ../../Make.ccmd
+
+test: $(TARG)
+ ./test.sh
diff --git a/src/cmd/godefs/test.sh b/src/cmd/godefs/test.sh
new file mode 100755
index 000000000..c035af8f4
--- /dev/null
+++ b/src/cmd/godefs/test.sh
@@ -0,0 +1,45 @@
+#!/usr/bin/env bash
+# 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.
+
+eval $(gomake --no-print-directory -f ../../Make.inc go-env)
+
+TMP="testdata_tmp.go"
+TEST="testdata.c"
+GOLDEN="testdata_${GOOS}_${GOARCH}.golden"
+
+case ${GOARCH} in
+"amd64") CCARG="-f-m64";;
+"386") CCARG="-f-m32";;
+*) CCARG="";;
+esac
+
+cleanup() {
+ rm ${TMP}
+}
+
+error() {
+ cleanup
+ echo $1
+ exit 1
+}
+
+if [ ! -e ${GOLDEN} ]; then
+ echo "skipping - no golden defined for this platform"
+ exit
+fi
+
+./godefs -g test ${CCARG} ${TEST} > ${TMP}
+if [ $? != 0 ]; then
+ error "Error: Could not run godefs for ${TEST}"
+fi
+
+diff ${TMP} ${GOLDEN}
+if [ $? != 0 ]; then
+ error "FAIL: godefs for ${TEST} did not match ${GOLDEN}"
+fi
+
+cleanup
+
+echo "PASS"
diff --git a/src/cmd/godefs/testdata.c b/src/cmd/godefs/testdata.c
new file mode 100644
index 000000000..3f459c41b
--- /dev/null
+++ b/src/cmd/godefs/testdata.c
@@ -0,0 +1,41 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <stdint.h>
+
+// Issue 432 - enum fields in struct can cause misaligned struct fields
+typedef enum {
+ a
+} T1;
+
+struct T2 {
+ uint8_t a;
+ T1 b;
+ T1 c;
+ uint16_t d;
+};
+
+typedef struct T2 T2;
+typedef T2 $T2;
+
+// Issue 1162 - structs with fields named Pad[0-9]+ conflict with field
+// names used by godefs for padding
+struct T3 {
+ uint8_t a;
+ int Pad0;
+};
+
+typedef struct T3 $T3;
+
+// Issue 1466 - forward references to types in stabs debug info were
+// always treated as enums
+struct T4 {};
+
+struct T5 {
+ struct T4 *a;
+};
+
+typedef struct T5 T5;
+typedef struct T4 $T4;
+typedef T5 $T5; \ No newline at end of file
diff --git a/src/cmd/godefs/testdata_darwin_386.golden b/src/cmd/godefs/testdata_darwin_386.golden
new file mode 100644
index 000000000..d929238b0
--- /dev/null
+++ b/src/cmd/godefs/testdata_darwin_386.golden
@@ -0,0 +1,31 @@
+// ./godefs -g test -f-m32 testdata.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+package test
+
+// Constants
+
+// Types
+
+type T2 struct {
+ A uint8;
+ Pad_godefs_0 [3]byte;
+ B uint32;
+ C uint32;
+ D uint16;
+ Pad_godefs_1 [2]byte;
+}
+
+type T3 struct {
+ A uint8;
+ Pad_godefs_0 [3]byte;
+ Pad0 int32;
+}
+
+type T4 struct {
+}
+
+type T5 struct {
+ A *T4;
+}
diff --git a/src/cmd/godefs/testdata_darwin_amd64.golden b/src/cmd/godefs/testdata_darwin_amd64.golden
new file mode 100644
index 000000000..a694f4a73
--- /dev/null
+++ b/src/cmd/godefs/testdata_darwin_amd64.golden
@@ -0,0 +1,31 @@
+// ./godefs -g test -f-m64 testdata.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+package test
+
+// Constants
+
+// Types
+
+type T2 struct {
+ A uint8;
+ Pad_godefs_0 [3]byte;
+ B uint32;
+ C uint32;
+ D uint16;
+ Pad_godefs_1 [2]byte;
+}
+
+type T3 struct {
+ A uint8;
+ Pad_godefs_0 [3]byte;
+ Pad0 int32;
+}
+
+type T4 struct {
+}
+
+type T5 struct {
+ A *T4;
+}
diff --git a/src/cmd/godoc/Makefile b/src/cmd/godoc/Makefile
index c4e0fd9f9..06a18be70 100644
--- a/src/cmd/godoc/Makefile
+++ b/src/cmd/godoc/Makefile
@@ -8,11 +8,13 @@ TARG=godoc
GOFILES=\
codewalk.go\
dirtrees.go\
+ filesystem.go\
format.go\
godoc.go\
index.go\
main.go\
mapping.go\
+ parser.go\
snippet.go\
spec.go\
utils.go\
diff --git a/src/cmd/godoc/codewalk.go b/src/cmd/godoc/codewalk.go
index 24087eb88..54bebe854 100644
--- a/src/cmd/godoc/codewalk.go
+++ b/src/cmd/godoc/codewalk.go
@@ -17,7 +17,6 @@ import (
"fmt"
"http"
"io"
- "io/ioutil"
"log"
"os"
"regexp"
@@ -42,7 +41,7 @@ func codewalk(w http.ResponseWriter, r *http.Request) {
}
// If directory exists, serve list of code walks.
- dir, err := os.Lstat(abspath)
+ dir, err := fs.Lstat(abspath)
if err == nil && dir.IsDirectory() {
codewalkDir(w, r, relpath, abspath)
return
@@ -114,8 +113,8 @@ func (st *Codestep) String() string {
// loadCodewalk reads a codewalk from the named XML file.
-func loadCodewalk(file string) (*Codewalk, os.Error) {
- f, err := os.Open(file)
+func loadCodewalk(filename string) (*Codewalk, os.Error) {
+ f, err := fs.Open(filename)
if err != nil {
return nil, err
}
@@ -125,7 +124,7 @@ func loadCodewalk(file string) (*Codewalk, os.Error) {
p.Entity = xml.HTMLEntity
err = p.Unmarshal(cw, nil)
if err != nil {
- return nil, &os.PathError{"parsing", file, err}
+ return nil, &os.PathError{"parsing", filename, err}
}
// Compute file list, evaluate line numbers for addresses.
@@ -135,8 +134,8 @@ func loadCodewalk(file string) (*Codewalk, os.Error) {
if i < 0 {
i = len(st.Src)
}
- file := st.Src[0:i]
- data, err := ioutil.ReadFile(absolutePath(file, *goroot))
+ filename := st.Src[0:i]
+ data, err := fs.ReadFile(absolutePath(filename, *goroot))
if err != nil {
st.Err = err
continue
@@ -158,8 +157,8 @@ func loadCodewalk(file string) (*Codewalk, os.Error) {
st.Hi = byteToLine(data, hi-1)
}
st.Data = data
- st.File = file
- m[file] = true
+ st.File = filename
+ m[filename] = true
}
// Make list of files
@@ -184,7 +183,7 @@ func codewalkDir(w http.ResponseWriter, r *http.Request, relpath, abspath string
Title string
}
- dir, err := ioutil.ReadDir(abspath)
+ dir, err := fs.ReadDir(abspath)
if err != nil {
log.Print(err)
serveError(w, r, relpath, err)
@@ -192,14 +191,15 @@ func codewalkDir(w http.ResponseWriter, r *http.Request, relpath, abspath string
}
var v vector.Vector
for _, fi := range dir {
+ name := fi.Name()
if fi.IsDirectory() {
- v.Push(&elem{fi.Name + "/", ""})
- } else if strings.HasSuffix(fi.Name, ".xml") {
- cw, err := loadCodewalk(abspath + "/" + fi.Name)
+ v.Push(&elem{name + "/", ""})
+ } else if strings.HasSuffix(name, ".xml") {
+ cw, err := loadCodewalk(abspath + "/" + name)
if err != nil {
continue
}
- v.Push(&elem{fi.Name[0 : len(fi.Name)-len(".xml")], cw.Title})
+ v.Push(&elem{name[0 : len(name)-len(".xml")], cw.Title})
}
}
@@ -216,7 +216,7 @@ func codewalkDir(w http.ResponseWriter, r *http.Request, relpath, abspath string
// the usual godoc HTML wrapper.
func codewalkFileprint(w http.ResponseWriter, r *http.Request, f string) {
abspath := absolutePath(f, *goroot)
- data, err := ioutil.ReadFile(abspath)
+ data, err := fs.ReadFile(abspath)
if err != nil {
log.Print(err)
serveError(w, r, f, err)
diff --git a/src/cmd/godoc/dirtrees.go b/src/cmd/godoc/dirtrees.go
index 97737ca5a..af44fa16a 100644
--- a/src/cmd/godoc/dirtrees.go
+++ b/src/cmd/godoc/dirtrees.go
@@ -11,9 +11,7 @@ import (
"go/doc"
"go/parser"
"go/token"
- "io/ioutil"
"log"
- "os"
"path/filepath"
"strings"
"unicode"
@@ -29,21 +27,23 @@ type Directory struct {
}
-func isGoFile(f *os.FileInfo) bool {
- return f.IsRegular() &&
- !strings.HasPrefix(f.Name, ".") && // ignore .files
- filepath.Ext(f.Name) == ".go"
+func isGoFile(fi FileInfo) bool {
+ name := fi.Name()
+ return fi.IsRegular() &&
+ !strings.HasPrefix(name, ".") && // ignore .files
+ filepath.Ext(name) == ".go"
}
-func isPkgFile(f *os.FileInfo) bool {
- return isGoFile(f) &&
- !strings.HasSuffix(f.Name, "_test.go") // ignore test files
+func isPkgFile(fi FileInfo) bool {
+ return isGoFile(fi) &&
+ !strings.HasSuffix(fi.Name(), "_test.go") // ignore test files
}
-func isPkgDir(f *os.FileInfo) bool {
- return f.IsDirectory() && len(f.Name) > 0 && f.Name[0] != '_'
+func isPkgDir(fi FileInfo) bool {
+ name := fi.Name()
+ return fi.IsDirectory() && len(name) > 0 && name[0] != '_'
}
@@ -101,12 +101,12 @@ func (b *treeBuilder) newDirTree(fset *token.FileSet, path, name string, depth i
return &Directory{depth, path, name, "", nil}
}
- list, err := ioutil.ReadDir(path)
+ list, err := fs.ReadDir(path)
if err != nil {
// newDirTree is called with a path that should be a package
// directory; errors here should not happen, but if they do,
// we want to know about them
- log.Printf("ioutil.ReadDir(%s): %s", path, err)
+ log.Printf("ReadDir(%s): %s", path, err)
}
// determine number of subdirectories and if there are package files
@@ -123,7 +123,7 @@ func (b *treeBuilder) newDirTree(fset *token.FileSet, path, name string, depth i
// though the directory doesn't contain any real package files - was bug)
if synopses[0] == "" {
// no "optimal" package synopsis yet; continue to collect synopses
- file, err := parser.ParseFile(fset, filepath.Join(path, d.Name), nil,
+ file, err := parser.ParseFile(fset, filepath.Join(path, d.Name()), nil,
parser.ParseComments|parser.PackageClauseOnly)
if err == nil {
hasPkgFiles = true
@@ -156,7 +156,8 @@ func (b *treeBuilder) newDirTree(fset *token.FileSet, path, name string, depth i
i := 0
for _, d := range list {
if isPkgDir(d) {
- dd := b.newDirTree(fset, filepath.Join(path, d.Name), d.Name, depth+1)
+ name := d.Name()
+ dd := b.newDirTree(fset, filepath.Join(path, name), name, depth+1)
if dd != nil {
dirs[i] = dd
i++
@@ -195,8 +196,8 @@ func (b *treeBuilder) newDirTree(fset *token.FileSet, path, name string, depth i
// (i.e., in this case the tree may contain directories w/o any package files).
//
func newDirectory(root string, pathFilter func(string) bool, maxDepth int) *Directory {
- // The root could be a symbolic link so use os.Stat not os.Lstat.
- d, err := os.Stat(root)
+ // The root could be a symbolic link so use Stat not Lstat.
+ d, err := fs.Stat(root)
// If we fail here, report detailed error messages; otherwise
// is is hard to see why a directory tree was not built.
switch {
@@ -213,7 +214,7 @@ func newDirectory(root string, pathFilter func(string) bool, maxDepth int) *Dire
b := treeBuilder{pathFilter, maxDepth}
// the file set provided is only for local parsing, no position
// information escapes and thus we don't need to save the set
- return b.newDirTree(token.NewFileSet(), root, d.Name, 0)
+ return b.newDirTree(token.NewFileSet(), root, d.Name(), 0)
}
diff --git a/src/cmd/godoc/filesystem.go b/src/cmd/godoc/filesystem.go
new file mode 100644
index 000000000..bf68378d4
--- /dev/null
+++ b/src/cmd/godoc/filesystem.go
@@ -0,0 +1,96 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file defines abstract file system access.
+
+package main
+
+import (
+ "io"
+ "io/ioutil"
+ "os"
+)
+
+
+// The FileInfo interface provides access to file information.
+type FileInfo interface {
+ Name() string
+ Size() int64
+ IsRegular() bool
+ IsDirectory() bool
+}
+
+
+// The FileSystem interface specifies the methods godoc is using
+// to access the file system for which it serves documentation.
+type FileSystem interface {
+ Open(path string) (io.ReadCloser, os.Error)
+ Lstat(path string) (FileInfo, os.Error)
+ Stat(path string) (FileInfo, os.Error)
+ ReadDir(path string) ([]FileInfo, os.Error)
+ ReadFile(path string) ([]byte, os.Error)
+}
+
+
+// ----------------------------------------------------------------------------
+// OS-specific FileSystem implementation
+
+var OS FileSystem = osFS{}
+
+
+// osFI is the OS-specific implementation of FileInfo.
+type osFI struct {
+ *os.FileInfo
+}
+
+
+func (fi osFI) Name() string {
+ return fi.FileInfo.Name
+}
+
+
+func (fi osFI) Size() int64 {
+ if fi.IsDirectory() {
+ return 0
+ }
+ return fi.FileInfo.Size
+}
+
+
+// osFS is the OS-specific implementation of FileSystem
+type osFS struct{}
+
+func (osFS) Open(path string) (io.ReadCloser, os.Error) {
+ return os.Open(path)
+}
+
+
+func (osFS) Lstat(path string) (FileInfo, os.Error) {
+ fi, err := os.Lstat(path)
+ return osFI{fi}, err
+}
+
+
+func (osFS) Stat(path string) (FileInfo, os.Error) {
+ fi, err := os.Stat(path)
+ return osFI{fi}, err
+}
+
+
+func (osFS) ReadDir(path string) ([]FileInfo, os.Error) {
+ l0, err := ioutil.ReadDir(path)
+ if err != nil {
+ return nil, err
+ }
+ l1 := make([]FileInfo, len(l0))
+ for i, e := range l0 {
+ l1[i] = osFI{e}
+ }
+ return l1, nil
+}
+
+
+func (osFS) ReadFile(path string) ([]byte, os.Error) {
+ return ioutil.ReadFile(path)
+}
diff --git a/src/cmd/godoc/godoc.go b/src/cmd/godoc/godoc.go
index f97c764f9..6987d911b 100644
--- a/src/cmd/godoc/godoc.go
+++ b/src/cmd/godoc/godoc.go
@@ -10,12 +10,10 @@ import (
"fmt"
"go/ast"
"go/doc"
- "go/parser"
"go/printer"
"go/token"
"http"
"io"
- "io/ioutil"
"log"
"os"
"path"
@@ -71,10 +69,11 @@ var (
maxResults = flag.Int("maxresults", 10000, "maximum number of full text search results shown")
// file system mapping
- fsMap Mapping // user-defined mapping
- fsTree RWValue // *Directory tree of packages, updated with each sync
- pathFilter RWValue // filter used when building fsMap directory trees
- fsModified RWValue // timestamp of last call to invalidateIndex
+ fs FileSystem // the underlying file system
+ fsMap Mapping // user-defined mapping
+ fsTree RWValue // *Directory tree of packages, updated with each sync
+ pathFilter RWValue // filter used when building fsMap directory trees
+ fsModified RWValue // timestamp of last call to invalidateIndex
// http handlers
fileServer http.Handler // default file server
@@ -147,13 +146,13 @@ func getPathFilter() func(string) bool {
// readDirList reads a file containing a newline-separated list
// of directory paths and returns the list of paths.
func readDirList(filename string) ([]string, os.Error) {
- contents, err := ioutil.ReadFile(filename)
+ contents, err := fs.ReadFile(filename)
if err != nil {
return nil, err
}
// create a sorted list of valid directory names
filter := func(path string) bool {
- d, e := os.Lstat(path)
+ d, e := fs.Lstat(path)
if e != nil && err == nil {
// remember first error and return it from readDirList
// so we have at least some information if things go bad
@@ -598,7 +597,7 @@ func timeFmt(w io.Writer, format string, x ...interface{}) {
// Template formatter for "dir/" format.
func dirslashFmt(w io.Writer, format string, x ...interface{}) {
- if x[0].(*os.FileInfo).IsDirectory() {
+ if x[0].(FileInfo).IsDirectory() {
w.Write([]byte{'/'})
}
}
@@ -642,12 +641,12 @@ func readTemplate(name string) *template.Template {
if *templateDir != "" {
defaultpath := path
path = filepath.Join(*templateDir, name)
- if _, err := os.Stat(path); err != nil {
+ if _, err := fs.Stat(path); err != nil {
log.Print("readTemplate:", err)
path = defaultpath
}
}
- data, err := ioutil.ReadFile(path)
+ data, err := fs.ReadFile(path)
if err != nil {
log.Fatalf("ReadFile %s: %v", path, err)
}
@@ -742,9 +741,9 @@ func extractString(src []byte, rx *regexp.Regexp) (s string) {
func serveHTMLDoc(w http.ResponseWriter, r *http.Request, abspath, relpath string) {
// get HTML body contents
- src, err := ioutil.ReadFile(abspath)
+ src, err := fs.ReadFile(abspath)
if err != nil {
- log.Printf("ioutil.ReadFile: %s", err)
+ log.Printf("ReadFile: %s", err)
serveError(w, r, relpath, err)
return
}
@@ -793,9 +792,9 @@ func redirect(w http.ResponseWriter, r *http.Request) (redirected bool) {
}
func serveTextFile(w http.ResponseWriter, r *http.Request, abspath, relpath, title string) {
- src, err := ioutil.ReadFile(abspath)
+ src, err := fs.ReadFile(abspath)
if err != nil {
- log.Printf("ioutil.ReadFile: %s", err)
+ log.Printf("ReadFile: %s", err)
serveError(w, r, relpath, err)
return
}
@@ -814,19 +813,13 @@ func serveDirectory(w http.ResponseWriter, r *http.Request, abspath, relpath str
return
}
- list, err := ioutil.ReadDir(abspath)
+ list, err := fs.ReadDir(abspath)
if err != nil {
- log.Printf("ioutil.ReadDir: %s", err)
+ log.Printf("ReadDir: %s", err)
serveError(w, r, relpath, err)
return
}
- for _, d := range list {
- if d.IsDirectory() {
- d.Size = 0
- }
- }
-
contents := applyTemplate(dirlistHTML, "dirlistHTML", list)
servePage(w, "Directory "+relpath, "", "", contents)
}
@@ -864,7 +857,7 @@ func serveFile(w http.ResponseWriter, r *http.Request) {
return
}
- dir, err := os.Lstat(abspath)
+ dir, err := fs.Lstat(abspath)
if err != nil {
log.Print(err)
serveError(w, r, relpath, err)
@@ -942,15 +935,15 @@ type httpHandler struct {
//
func (h *httpHandler) getPageInfo(abspath, relpath, pkgname string, mode PageInfoMode) PageInfo {
// filter function to select the desired .go files
- filter := func(d *os.FileInfo) bool {
+ filter := func(d FileInfo) bool {
// If we are looking at cmd documentation, only accept
// the special fakePkgFile containing the documentation.
- return isPkgFile(d) && (h.isPkg || d.Name == fakePkgFile)
+ return isPkgFile(d) && (h.isPkg || d.Name() == fakePkgFile)
}
// get package ASTs
fset := token.NewFileSet()
- pkgs, err := parser.ParseDir(fset, abspath, filter, parser.ParseComments)
+ pkgs, err := parseDir(fset, abspath, filter)
if err != nil && pkgs == nil {
// only report directory read errors, ignore parse errors
// (may be able to extract partial package information)
diff --git a/src/cmd/godoc/index.go b/src/cmd/godoc/index.go
index 5938d0b74..61caee101 100644
--- a/src/cmd/godoc/index.go
+++ b/src/cmd/godoc/index.go
@@ -45,7 +45,6 @@ import (
"go/token"
"go/scanner"
"index/suffixarray"
- "io/ioutil"
"os"
"path/filepath"
"regexp"
@@ -624,7 +623,7 @@ func pkgName(filename string) string {
// failed (that is, if the file was not added), it returns file == nil.
func (x *Indexer) addFile(filename string, goFile bool) (file *token.File, ast *ast.File) {
// open file
- f, err := os.Open(filename)
+ f, err := fs.Open(filename)
if err != nil {
return
}
@@ -727,12 +726,12 @@ func isWhitelisted(filename string) bool {
}
-func (x *Indexer) visitFile(dirname string, f *os.FileInfo, fulltextIndex bool) {
+func (x *Indexer) visitFile(dirname string, f FileInfo, fulltextIndex bool) {
if !f.IsRegular() {
return
}
- filename := filepath.Join(dirname, f.Name)
+ filename := filepath.Join(dirname, f.Name())
goFile := false
switch {
@@ -745,7 +744,7 @@ func (x *Indexer) visitFile(dirname string, f *os.FileInfo, fulltextIndex bool)
}
goFile = true
- case !fulltextIndex || !isWhitelisted(f.Name):
+ case !fulltextIndex || !isWhitelisted(f.Name()):
return
}
@@ -804,7 +803,7 @@ func NewIndex(dirnames <-chan string, fulltextIndex bool) *Index {
// index all files in the directories given by dirnames
for dirname := range dirnames {
- list, err := ioutil.ReadDir(dirname)
+ list, err := fs.ReadDir(dirname)
if err != nil {
continue // ignore this directory
}
diff --git a/src/cmd/godoc/main.go b/src/cmd/godoc/main.go
index 967ea8727..55f6031bc 100644
--- a/src/cmd/godoc/main.go
+++ b/src/cmd/godoc/main.go
@@ -222,6 +222,10 @@ func main() {
flag.Usage = usage
flag.Parse()
+ // Determine file system to use.
+ // TODO(gri) Complete this - for now we only have one.
+ fs = OS
+
// Clean goroot: normalize path separator.
*goroot = filepath.Clean(*goroot)
diff --git a/src/cmd/godoc/mapping.go b/src/cmd/godoc/mapping.go
index 6ae9032e4..73f1881a2 100644
--- a/src/cmd/godoc/mapping.go
+++ b/src/cmd/godoc/mapping.go
@@ -9,7 +9,6 @@ package main
import (
"fmt"
"io"
- "os"
"path"
"path/filepath"
"sort"
@@ -174,7 +173,7 @@ func (m *Mapping) ToAbsolute(spath string) string {
continue // no match
}
abspath := filepath.Join(e.path, tail)
- if _, err := os.Stat(abspath); err == nil {
+ if _, err := fs.Stat(abspath); err == nil {
return abspath
}
}
diff --git a/src/cmd/godoc/parser.go b/src/cmd/godoc/parser.go
new file mode 100644
index 000000000..423db222d
--- /dev/null
+++ b/src/cmd/godoc/parser.go
@@ -0,0 +1,69 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains support functions for parsing .go files.
+// Similar functionality is found in package go/parser but the
+// functions here operate using godoc's file system fs instead
+// of calling the OS's file operations directly.
+
+package main
+
+import (
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "os"
+ "path/filepath"
+)
+
+func parseFiles(fset *token.FileSet, filenames []string) (pkgs map[string]*ast.Package, first os.Error) {
+ pkgs = make(map[string]*ast.Package)
+ for _, filename := range filenames {
+ src, err := fs.ReadFile(filename)
+ if err != nil {
+ if first == nil {
+ first = err
+ }
+ continue
+ }
+
+ file, err := parser.ParseFile(fset, filename, src, parser.ParseComments)
+ if err != nil {
+ if first == nil {
+ first = err
+ }
+ continue
+ }
+
+ name := file.Name.Name
+ pkg, found := pkgs[name]
+ if !found {
+ // TODO(gri) Use NewPackage here; reconsider ParseFiles API.
+ pkg = &ast.Package{name, nil, nil, make(map[string]*ast.File)}
+ pkgs[name] = pkg
+ }
+ pkg.Files[filename] = file
+ }
+ return
+}
+
+
+func parseDir(fset *token.FileSet, path string, filter func(FileInfo) bool) (map[string]*ast.Package, os.Error) {
+ list, err := fs.ReadDir(path)
+ if err != nil {
+ return nil, err
+ }
+
+ filenames := make([]string, len(list))
+ i := 0
+ for _, d := range list {
+ if filter == nil || filter(d) {
+ filenames[i] = filepath.Join(path, d.Name())
+ i++
+ }
+ }
+ filenames = filenames[0:i]
+
+ return parseFiles(fset, filenames)
+}
diff --git a/src/cmd/godoc/utils.go b/src/cmd/godoc/utils.go
index 593b51ce0..660bf6d04 100644
--- a/src/cmd/godoc/utils.go
+++ b/src/cmd/godoc/utils.go
@@ -44,6 +44,10 @@ func (v *RWValue) get() (interface{}, int64) {
}
+// TODO(gri) For now, using os.Getwd() is ok here since the functionality
+// based on this code is not invoked for the appengine version,
+// but this is fragile. Determine what the right thing to do is,
+// here (possibly have some Getwd-equivalent in FileSystem).
var cwd, _ = os.Getwd() // ignore errors
// canonicalizePaths takes a list of (directory/file) paths and returns
@@ -95,6 +99,7 @@ func canonicalizePaths(list []string, filter func(path string) bool) []string {
// atomically renames that file to the file named by filename.
//
func writeFileAtomically(filename string, data []byte) os.Error {
+ // TODO(gri) this won't work on appengine
f, err := ioutil.TempFile(filepath.Split(filename))
if err != nil {
return err
@@ -155,7 +160,7 @@ func isTextFile(filename string) bool {
// the extension is not known; read an initial chunk
// of the file and check if it looks like text
- f, err := os.Open(filename)
+ f, err := fs.Open(filename)
if err != nil {
return false
}
diff --git a/src/cmd/gofix/Makefile b/src/cmd/gofix/Makefile
index d19de5c4f..b157649e8 100644
--- a/src/cmd/gofix/Makefile
+++ b/src/cmd/gofix/Makefile
@@ -9,8 +9,10 @@ GOFILES=\
fix.go\
netdial.go\
main.go\
+ oserrorstring.go\
osopen.go\
httpfinalurl.go\
+ httpheaders.go\
httpserver.go\
procattr.go\
reflect.go\
diff --git a/src/cmd/gofix/httpfinalurl.go b/src/cmd/gofix/httpfinalurl.go
index 53642b22f..9e6cbf6bc 100644
--- a/src/cmd/gofix/httpfinalurl.go
+++ b/src/cmd/gofix/httpfinalurl.go
@@ -13,7 +13,7 @@ var httpFinalURLFix = fix{
httpfinalurl,
`Adapt http Get calls to not have a finalURL result parameter.
- http://codereview.appspot.com/4535056/
+http://codereview.appspot.com/4535056/
`,
}
diff --git a/src/cmd/gofix/httpheaders.go b/src/cmd/gofix/httpheaders.go
new file mode 100644
index 000000000..8a9080e8e
--- /dev/null
+++ b/src/cmd/gofix/httpheaders.go
@@ -0,0 +1,66 @@
+// 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 main
+
+import (
+ "go/ast"
+)
+
+var httpHeadersFix = fix{
+ "httpheaders",
+ httpheaders,
+ `Rename http Referer, UserAgent, Cookie, SetCookie, which are now methods.
+
+http://codereview.appspot.com/4620049/
+`,
+}
+
+func init() {
+ register(httpHeadersFix)
+}
+
+func httpheaders(f *ast.File) bool {
+ if !imports(f, "http") {
+ return false
+ }
+
+ called := make(map[ast.Node]bool)
+ walk(f, func(ni interface{}) {
+ switch n := ni.(type) {
+ case *ast.CallExpr:
+ called[n.Fun] = true
+ }
+ })
+
+ fixed := false
+ typeof := typecheck(headerTypeConfig, f)
+ walk(f, func(ni interface{}) {
+ switch n := ni.(type) {
+ case *ast.SelectorExpr:
+ if called[n] {
+ break
+ }
+ if t := typeof[n.X]; t != "*http.Request" && t != "*http.Response" {
+ break
+ }
+ switch n.Sel.Name {
+ case "Referer", "UserAgent":
+ n.Sel.Name += "()"
+ fixed = true
+ case "Cookie":
+ n.Sel.Name = "Cookies()"
+ fixed = true
+ }
+ }
+ })
+ return fixed
+}
+
+var headerTypeConfig = &TypeConfig{
+ Type: map[string]*Type{
+ "*http.Request": &Type{},
+ "*http.Response": &Type{},
+ },
+}
diff --git a/src/cmd/gofix/httpheaders_test.go b/src/cmd/gofix/httpheaders_test.go
new file mode 100644
index 000000000..cc82b5893
--- /dev/null
+++ b/src/cmd/gofix/httpheaders_test.go
@@ -0,0 +1,73 @@
+// 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 main
+
+func init() {
+ addTestCases(httpHeadersTests)
+}
+
+var httpHeadersTests = []testCase{
+ {
+ Name: "httpheaders.0",
+ In: `package headertest
+
+import (
+ "http"
+)
+
+type Other struct {
+ Referer string
+ UserAgent string
+ Cookie []*http.Cookie
+}
+
+func f(req *http.Request, res *http.Response, other *Other) {
+ _ = req.Referer
+ _ = req.UserAgent
+ _ = req.Cookie
+
+ _ = res.Cookie
+
+ _ = other.Referer
+ _ = other.UserAgent
+ _ = other.Cookie
+
+ _ = req.Referer()
+ _ = req.UserAgent()
+ _ = req.Cookies()
+ _ = res.Cookies()
+}
+`,
+ Out: `package headertest
+
+import (
+ "http"
+)
+
+type Other struct {
+ Referer string
+ UserAgent string
+ Cookie []*http.Cookie
+}
+
+func f(req *http.Request, res *http.Response, other *Other) {
+ _ = req.Referer()
+ _ = req.UserAgent()
+ _ = req.Cookies()
+
+ _ = res.Cookies()
+
+ _ = other.Referer
+ _ = other.UserAgent
+ _ = other.Cookie
+
+ _ = req.Referer()
+ _ = req.UserAgent()
+ _ = req.Cookies()
+ _ = res.Cookies()
+}
+`,
+ },
+}
diff --git a/src/cmd/gofix/main.go b/src/cmd/gofix/main.go
index 1b091c18a..05495bc0d 100644
--- a/src/cmd/gofix/main.go
+++ b/src/cmd/gofix/main.go
@@ -123,7 +123,7 @@ func processFile(filename string, useStdin bool) os.Error {
newFile := file
fixed := false
for _, fix := range fixes {
- if allowed != nil && !allowed[fix.desc] {
+ if allowed != nil && !allowed[fix.name] {
continue
}
if fix.f(newFile) {
diff --git a/src/cmd/gofix/oserrorstring.go b/src/cmd/gofix/oserrorstring.go
new file mode 100644
index 000000000..5e61ab952
--- /dev/null
+++ b/src/cmd/gofix/oserrorstring.go
@@ -0,0 +1,75 @@
+// 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 main
+
+import (
+ "go/ast"
+)
+
+var oserrorstringFix = fix{
+ "oserrorstring",
+ oserrorstring,
+ `Replace os.ErrorString() conversions with calls to os.NewError().
+
+http://codereview.appspot.com/4607052
+`,
+}
+
+func init() {
+ register(oserrorstringFix)
+}
+
+func oserrorstring(f *ast.File) bool {
+ if !imports(f, "os") {
+ return false
+ }
+
+ fixed := false
+ walk(f, func(n interface{}) {
+ // The conversion os.ErrorString(x) looks like a call
+ // of os.ErrorString with one argument.
+ if call := callExpr(n, "os", "ErrorString"); call != nil {
+ // os.ErrorString(args) -> os.NewError(args)
+ call.Fun.(*ast.SelectorExpr).Sel.Name = "NewError"
+ // os.ErrorString(args) -> os.NewError(args)
+ call.Fun.(*ast.SelectorExpr).Sel.Name = "NewError"
+ fixed = true
+ return
+ }
+
+ // Remove os.Error type from variable declarations initialized
+ // with an os.NewError.
+ // (An *ast.ValueSpec may also be used in a const declaration
+ // but those won't be initialized with a call to os.NewError.)
+ if spec, ok := n.(*ast.ValueSpec); ok &&
+ len(spec.Names) == 1 &&
+ isPkgDot(spec.Type, "os", "Error") &&
+ len(spec.Values) == 1 &&
+ callExpr(spec.Values[0], "os", "NewError") != nil {
+ // var name os.Error = os.NewError(x) ->
+ // var name = os.NewError(x)
+ spec.Type = nil
+ fixed = true
+ return
+ }
+
+ // Other occurrences of os.ErrorString are not fixed
+ // but they are rare.
+
+ })
+ return fixed
+}
+
+
+// callExpr returns the call expression if x is a call to pkg.name with one argument;
+// otherwise it returns nil.
+func callExpr(x interface{}, pkg, name string) *ast.CallExpr {
+ if call, ok := x.(*ast.CallExpr); ok &&
+ len(call.Args) == 1 &&
+ isPkgDot(call.Fun, pkg, name) {
+ return call
+ }
+ return nil
+}
diff --git a/src/cmd/gofix/oserrorstring_test.go b/src/cmd/gofix/oserrorstring_test.go
new file mode 100644
index 000000000..070d9222b
--- /dev/null
+++ b/src/cmd/gofix/oserrorstring_test.go
@@ -0,0 +1,57 @@
+// 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 main
+
+func init() {
+ addTestCases(oserrorstringTests)
+}
+
+var oserrorstringTests = []testCase{
+ {
+ Name: "oserrorstring.0",
+ In: `package main
+
+import "os"
+
+var _ = os.ErrorString("foo")
+var _ os.Error = os.ErrorString("bar1")
+var _ os.Error = os.NewError("bar2")
+var _ os.Error = MyError("bal") // don't rewrite this one
+
+var (
+ _ = os.ErrorString("foo")
+ _ os.Error = os.ErrorString("bar1")
+ _ os.Error = os.NewError("bar2")
+ _ os.Error = MyError("bal") // don't rewrite this one
+)
+
+func _() (err os.Error) {
+ err = os.ErrorString("foo")
+ return os.ErrorString("foo")
+}
+`,
+ Out: `package main
+
+import "os"
+
+var _ = os.NewError("foo")
+var _ = os.NewError("bar1")
+var _ = os.NewError("bar2")
+var _ os.Error = MyError("bal") // don't rewrite this one
+
+var (
+ _ = os.NewError("foo")
+ _ = os.NewError("bar1")
+ _ = os.NewError("bar2")
+ _ os.Error = MyError("bal") // don't rewrite this one
+)
+
+func _() (err os.Error) {
+ err = os.NewError("foo")
+ return os.NewError("foo")
+}
+`,
+ },
+}
diff --git a/src/cmd/gofix/osopen.go b/src/cmd/gofix/osopen.go
index 8eb5d0655..56147c390 100644
--- a/src/cmd/gofix/osopen.go
+++ b/src/cmd/gofix/osopen.go
@@ -13,7 +13,7 @@ var osopenFix = fix{
osopen,
`Adapt os.Open calls to new, easier API and rename O_CREAT O_CREATE.
- http://codereview.appspot.com/4357052
+http://codereview.appspot.com/4357052
`,
}
diff --git a/src/cmd/gofix/testdata/reflect.decoder.go.out b/src/cmd/gofix/testdata/reflect.decoder.go.out
index 170eedb05..ece88ecbe 100644
--- a/src/cmd/gofix/testdata/reflect.decoder.go.out
+++ b/src/cmd/gofix/testdata/reflect.decoder.go.out
@@ -44,7 +44,7 @@ func NewDecoder(r io.Reader) *Decoder {
func (dec *Decoder) recvType(id typeId) {
// Have we already seen this type? That's an error
if id < firstUserId || dec.wireType[id] != nil {
- dec.err = os.ErrorString("gob: duplicate type received")
+ dec.err = os.NewError("gob: duplicate type received")
return
}
@@ -143,7 +143,7 @@ func (dec *Decoder) decodeTypeSequence(isInterface bool) typeId {
// will be absorbed by recvMessage.)
if dec.buf.Len() > 0 {
if !isInterface {
- dec.err = os.ErrorString("extra data in buffer")
+ dec.err = os.NewError("extra data in buffer")
break
}
dec.nextUint()
@@ -165,7 +165,7 @@ func (dec *Decoder) Decode(e interface{}) os.Error {
// If e represents a value as opposed to a pointer, the answer won't
// get back to the caller. Make sure it's a pointer.
if value.Type().Kind() != reflect.Ptr {
- dec.err = os.ErrorString("gob: attempt to decode into a non-pointer")
+ dec.err = os.NewError("gob: attempt to decode into a non-pointer")
return dec.err
}
return dec.DecodeValue(value)
diff --git a/src/cmd/gofix/testdata/reflect.encoder.go.out b/src/cmd/gofix/testdata/reflect.encoder.go.out
index 781ef6504..925d39301 100644
--- a/src/cmd/gofix/testdata/reflect.encoder.go.out
+++ b/src/cmd/gofix/testdata/reflect.encoder.go.out
@@ -50,7 +50,7 @@ func (enc *Encoder) popWriter() {
}
func (enc *Encoder) badType(rt reflect.Type) {
- enc.setError(os.ErrorString("gob: can't encode type " + rt.String()))
+ enc.setError(os.NewError("gob: can't encode type " + rt.String()))
}
func (enc *Encoder) setError(err os.Error) {
diff --git a/src/cmd/gofix/testdata/reflect.export.go.out b/src/cmd/gofix/testdata/reflect.export.go.out
index 486a812e2..460edb40b 100644
--- a/src/cmd/gofix/testdata/reflect.export.go.out
+++ b/src/cmd/gofix/testdata/reflect.export.go.out
@@ -343,20 +343,20 @@ func (exp *Exporter) Sync(timeout int64) os.Error {
func checkChan(chT interface{}, dir Dir) (reflect.Value, os.Error) {
chanType := reflect.TypeOf(chT)
if chanType.Kind() != reflect.Chan {
- return reflect.Value{}, os.ErrorString("not a channel")
+ return reflect.Value{}, os.NewError("not a channel")
}
if dir != Send && dir != Recv {
- return reflect.Value{}, os.ErrorString("unknown channel direction")
+ return reflect.Value{}, os.NewError("unknown channel direction")
}
switch chanType.ChanDir() {
case reflect.BothDir:
case reflect.SendDir:
if dir != Recv {
- return reflect.Value{}, os.ErrorString("to import/export with Send, must provide <-chan")
+ return reflect.Value{}, os.NewError("to import/export with Send, must provide <-chan")
}
case reflect.RecvDir:
if dir != Send {
- return reflect.Value{}, os.ErrorString("to import/export with Recv, must provide chan<-")
+ return reflect.Value{}, os.NewError("to import/export with Recv, must provide chan<-")
}
}
return reflect.ValueOf(chT), nil
@@ -376,7 +376,7 @@ func (exp *Exporter) Export(name string, chT interface{}, dir Dir) os.Error {
defer exp.mu.Unlock()
_, present := exp.names[name]
if present {
- return os.ErrorString("channel name already being exported:" + name)
+ return os.NewError("channel name already being exported:" + name)
}
exp.names[name] = &chanDir{ch, dir}
return nil
@@ -393,7 +393,7 @@ func (exp *Exporter) Hangup(name string) os.Error {
// TODO drop all instances of channel from client sets
exp.mu.Unlock()
if !ok {
- return os.ErrorString("netchan export: hangup: no such channel: " + name)
+ return os.NewError("netchan export: hangup: no such channel: " + name)
}
chDir.ch.Close()
return nil
diff --git a/src/cmd/gofix/testdata/reflect.print.go.out b/src/cmd/gofix/testdata/reflect.print.go.out
index 079948cca..10379bd20 100644
--- a/src/cmd/gofix/testdata/reflect.print.go.out
+++ b/src/cmd/gofix/testdata/reflect.print.go.out
@@ -185,7 +185,7 @@ func Sprintf(format string, a ...interface{}) string {
// Errorf formats according to a format specifier and returns the string
// converted to an os.ErrorString, which satisfies the os.Error interface.
func Errorf(format string, a ...interface{}) os.Error {
- return os.ErrorString(Sprintf(format, a...))
+ return os.NewError(Sprintf(format, a...))
}
// These routines do not take a format string
diff --git a/src/cmd/gofix/testdata/reflect.read.go.out b/src/cmd/gofix/testdata/reflect.read.go.out
index 554b2a61b..a6b126744 100644
--- a/src/cmd/gofix/testdata/reflect.read.go.out
+++ b/src/cmd/gofix/testdata/reflect.read.go.out
@@ -244,7 +244,7 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
switch v := val; v.Kind() {
default:
- return os.ErrorString("unknown type " + v.Type().String())
+ return os.NewError("unknown type " + v.Type().String())
case reflect.Slice:
typ := v.Type()
@@ -483,7 +483,7 @@ Loop:
case reflect.Invalid:
// Probably a comment, handled below
default:
- return os.ErrorString("cannot happen: unknown type " + t.Type().String())
+ return os.NewError("cannot happen: unknown type " + t.Type().String())
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if !getInt64() {
return err
diff --git a/src/cmd/gofix/testdata/reflect.scan.go.out b/src/cmd/gofix/testdata/reflect.scan.go.out
index 42bc52c92..2b07115e9 100644
--- a/src/cmd/gofix/testdata/reflect.scan.go.out
+++ b/src/cmd/gofix/testdata/reflect.scan.go.out
@@ -167,7 +167,7 @@ type ssave struct {
// satisfies io.Reader. It will never be called when used as
// intended, so there is no need to make it actually work.
func (s *ss) Read(buf []byte) (n int, err os.Error) {
- return 0, os.ErrorString("ScanState's Read should not be called. Use ReadRune")
+ return 0, os.NewError("ScanState's Read should not be called. Use ReadRune")
}
func (s *ss) ReadRune() (rune int, size int, err os.Error) {
@@ -240,7 +240,7 @@ func (s *ss) error(err os.Error) {
}
func (s *ss) errorString(err string) {
- panic(scanError{os.ErrorString(err)})
+ panic(scanError{os.NewError(err)})
}
func (s *ss) Token(skipSpace bool, f func(int) bool) (tok []byte, err os.Error) {
@@ -426,8 +426,8 @@ func (s *ss) typeError(field interface{}, expected string) {
s.errorString("expected field of type pointer to " + expected + "; found " + reflect.TypeOf(field).String())
}
-var complexError = os.ErrorString("syntax error scanning complex number")
-var boolError = os.ErrorString("syntax error scanning boolean")
+var complexError = os.NewError("syntax error scanning complex number")
+var boolError = os.NewError("syntax error scanning boolean")
// consume reads the next rune in the input and reports whether it is in the ok string.
// If accept is true, it puts the character into the input token.
diff --git a/src/cmd/gofix/testdata/reflect.type.go.out b/src/cmd/gofix/testdata/reflect.type.go.out
index a39b074fe..9cd78296d 100644
--- a/src/cmd/gofix/testdata/reflect.type.go.out
+++ b/src/cmd/gofix/testdata/reflect.type.go.out
@@ -67,7 +67,7 @@ func validUserType(rt reflect.Type) (ut *userTypeInfo, err os.Error) {
ut.base = pt.Elem()
if ut.base == slowpoke { // ut.base lapped slowpoke
// recursive pointer type.
- return nil, os.ErrorString("can't represent recursive pointer type " + ut.base.String())
+ return nil, os.NewError("can't represent recursive pointer type " + ut.base.String())
}
if ut.indir%2 == 0 {
slowpoke = slowpoke.Elem()
@@ -524,7 +524,7 @@ func newTypeObject(name string, ut *userTypeInfo, rt reflect.Type) (gobType, os.
return st, nil
default:
- return nil, os.ErrorString("gob NewTypeObject can't handle type: " + rt.String())
+ return nil, os.NewError("gob NewTypeObject can't handle type: " + rt.String())
}
return nil, nil
}
diff --git a/src/cmd/goinstall/Makefile b/src/cmd/goinstall/Makefile
index 202797cd5..f61354f39 100644
--- a/src/cmd/goinstall/Makefile
+++ b/src/cmd/goinstall/Makefile
@@ -9,22 +9,5 @@ GOFILES=\
download.go\
main.go\
make.go\
- parse.go\
- path.go\
- syslist.go\
-
-CLEANFILES+=syslist.go
include ../../Make.cmd
-
-syslist.go:
- echo '// Generated automatically by make.' >$@
- echo 'package main' >>$@
- echo 'const goosList = "$(GOOS_LIST)"' >>$@
- echo 'const goarchList = "$(GOARCH_LIST)"' >>$@
-
-test:
- gotest
-
-testshort:
- gotest -test.short
diff --git a/src/cmd/goinstall/doc.go b/src/cmd/goinstall/doc.go
index 13c37d0a2..52b09d37e 100644
--- a/src/cmd/goinstall/doc.go
+++ b/src/cmd/goinstall/doc.go
@@ -15,7 +15,9 @@ Flags and default settings:
-a=false install all previously installed packages
-clean=false clean the package directory before installing
-dashboard=true tally public packages on godashboard.appspot.com
+ -install=true build and install the package and its dependencies
-log=true log installed packages to $GOROOT/goinstall.log for use by -a
+ -nuke=false remove the target object and clean before installing
-u=false update already-downloaded packages
-v=false verbose operation
@@ -61,7 +63,7 @@ if necessary. The recognized code hosting sites are:
import "project.googlecode.com/svn/trunk"
import "project.googlecode.com/svn/trunk/sub/directory"
- Launchpad
+ Launchpad (Bazaar)
import "launchpad.net/project"
import "launchpad.net/project/series"
@@ -85,7 +87,7 @@ system, typically HEAD for git, tip for Mercurial.
After a successful download and installation of a publicly accessible
remote package, goinstall reports the installation to godashboard.appspot.com,
which increments a count associated with the package and the time
-of its most recent installation. This mechanism powers the package list
+of its most recent installation. This mechanism powers the package list
at http://godashboard.appspot.com/package, allowing Go programmers
to learn about popular packages that might be worth looking at.
The -dashboard=false flag disables this reporting.
@@ -94,11 +96,7 @@ By default, goinstall prints output only when it encounters an error.
The -v flag causes goinstall to print information about packages
being considered and installed.
-Goinstall does not attempt to be a replacement for make.
-Instead, it invokes "make install" after locating the package sources.
-For local packages without a Makefile and all remote packages,
-goinstall creates and uses a temporary Makefile constructed from
-the import path and the list of Go files in the package.
+Goinstall does not use make. Makefiles are ignored by goinstall.
The GOPATH Environment Variable
diff --git a/src/cmd/goinstall/download.go b/src/cmd/goinstall/download.go
index 2edf85efd..d209fa82b 100644
--- a/src/cmd/goinstall/download.go
+++ b/src/cmd/goinstall/download.go
@@ -31,74 +31,15 @@ func maybeReportToDashboard(path string) {
}
}
-var vcsPatterns = map[string]*regexp.Regexp{
- "googlecode": regexp.MustCompile(`^([a-z0-9\-]+\.googlecode\.com/(svn|hg))(/[a-z0-9A-Z_.\-/]*)?$`),
- "github": regexp.MustCompile(`^(github\.com/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]*)?$`),
- "bitbucket": regexp.MustCompile(`^(bitbucket\.org/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]*)?$`),
- "launchpad": regexp.MustCompile(`^(launchpad\.net/([a-z0-9A-Z_.\-]+(/[a-z0-9A-Z_.\-]+)?|~[a-z0-9A-Z_.\-]+/(\+junk|[a-z0-9A-Z_.\-]+)/[a-z0-9A-Z_.\-]+))(/[a-z0-9A-Z_.\-/]+)?$`),
-}
-
-// isRemote returns true if the provided package path
-// matches one of the supported remote repositories.
-func isRemote(pkg string) bool {
- for _, r := range vcsPatterns {
- if r.MatchString(pkg) {
- return true
- }
- }
- return false
-}
-
-// download checks out or updates pkg from the remote server.
-func download(pkg, srcDir string) os.Error {
- if strings.Contains(pkg, "..") {
- return os.ErrorString("invalid path (contains ..)")
- }
- if m := vcsPatterns["bitbucket"].FindStringSubmatch(pkg); m != nil {
- if err := vcsCheckout(&hg, srcDir, m[1], "http://"+m[1], m[1]); err != nil {
- return err
- }
- return nil
- }
- if m := vcsPatterns["googlecode"].FindStringSubmatch(pkg); m != nil {
- var v *vcs
- switch m[2] {
- case "hg":
- v = &hg
- case "svn":
- v = &svn
- default:
- // regexp only allows hg, svn to get through
- panic("missing case in download: " + pkg)
- }
- if err := vcsCheckout(v, srcDir, m[1], "https://"+m[1], m[1]); err != nil {
- return err
- }
- return nil
- }
- if m := vcsPatterns["github"].FindStringSubmatch(pkg); m != nil {
- if strings.HasSuffix(m[1], ".git") {
- return os.ErrorString("repository " + pkg + " should not have .git suffix")
- }
- if err := vcsCheckout(&git, srcDir, m[1], "http://"+m[1]+".git", m[1]); err != nil {
- return err
- }
- return nil
- }
- if m := vcsPatterns["launchpad"].FindStringSubmatch(pkg); m != nil {
- // Either lp.net/<project>[/<series>[/<path>]]
- // or lp.net/~<user or team>/<project>/<branch>[/<path>]
- if err := vcsCheckout(&bzr, srcDir, m[1], "https://"+m[1], m[1]); err != nil {
- return err
- }
- return nil
- }
- return os.ErrorString("unknown repository: " + pkg)
+type host struct {
+ pattern *regexp.Regexp
+ protocol string
}
// a vcs represents a version control system
// like Mercurial, Git, or Subversion.
type vcs struct {
+ name string
cmd string
metadir string
checkout string
@@ -110,9 +51,19 @@ type vcs struct {
log string
logLimitFlag string
logReleaseFlag string
+ check string
+ protocols []string
+ suffix string
+ defaultHosts []host
+}
+
+type vcsMatch struct {
+ *vcs
+ prefix, repo string
}
var hg = vcs{
+ name: "Mercurial",
cmd: "hg",
metadir: ".hg",
checkout: "checkout",
@@ -123,9 +74,16 @@ var hg = vcs{
log: "log",
logLimitFlag: "-l1",
logReleaseFlag: "-rrelease",
+ check: "identify",
+ protocols: []string{"http"},
+ defaultHosts: []host{
+ {regexp.MustCompile(`^([a-z0-9\-]+\.googlecode\.com/hg)(/[a-z0-9A-Z_.\-/]*)?$`), "https"},
+ {regexp.MustCompile(`^(bitbucket\.org/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]*)?$`), "http"},
+ },
}
var git = vcs{
+ name: "Git",
cmd: "git",
metadir: ".git",
checkout: "checkout",
@@ -136,9 +94,16 @@ var git = vcs{
log: "show-ref",
logLimitFlag: "",
logReleaseFlag: "release",
+ check: "peek-remote",
+ protocols: []string{"git", "http"},
+ suffix: ".git",
+ defaultHosts: []host{
+ {regexp.MustCompile(`^(github\.com/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]*)?$`), "http"},
+ },
}
var svn = vcs{
+ name: "Subversion",
cmd: "svn",
metadir: ".svn",
checkout: "checkout",
@@ -148,9 +113,15 @@ var svn = vcs{
log: "log",
logLimitFlag: "-l1",
logReleaseFlag: "release",
+ check: "info",
+ protocols: []string{"http", "svn"},
+ defaultHosts: []host{
+ {regexp.MustCompile(`^([a-z0-9\-]+\.googlecode\.com/svn)(/[a-z0-9A-Z_.\-/]*)?$`), "https"},
+ },
}
var bzr = vcs{
+ name: "Bazaar",
cmd: "bzr",
metadir: ".bzr",
checkout: "update",
@@ -162,6 +133,51 @@ var bzr = vcs{
log: "log",
logLimitFlag: "-l1",
logReleaseFlag: "-rrelease",
+ check: "info",
+ protocols: []string{"http", "bzr"},
+ defaultHosts: []host{
+ {regexp.MustCompile(`^(launchpad\.net/([a-z0-9A-Z_.\-]+(/[a-z0-9A-Z_.\-]+)?|~[a-z0-9A-Z_.\-]+/(\+junk|[a-z0-9A-Z_.\-]+)/[a-z0-9A-Z_.\-]+))(/[a-z0-9A-Z_.\-/]+)?$`), "https"},
+ },
+}
+
+var vcsList = []*vcs{&git, &hg, &bzr, &svn}
+
+// isRemote returns true if the first part of the package name looks like a
+// hostname - i.e. contains at least one '.' and the last part is at least 2
+// characters.
+func isRemote(pkg string) bool {
+ parts := strings.Split(pkg, "/", 2)
+ if len(parts) != 2 {
+ return false
+ }
+ parts = strings.Split(parts[0], ".", -1)
+ if len(parts) < 2 || len(parts[len(parts)-1]) < 2 {
+ return false
+ }
+ return true
+}
+
+// download checks out or updates pkg from the remote server.
+func download(pkg, srcDir string) os.Error {
+ if strings.Contains(pkg, "..") {
+ return os.NewError("invalid path (contains ..)")
+ }
+ var m *vcsMatch
+ for _, v := range vcsList {
+ for _, host := range v.defaultHosts {
+ if hm := host.pattern.FindStringSubmatch(pkg); hm != nil {
+ if v.suffix != "" && strings.HasSuffix(hm[1], v.suffix) {
+ return os.NewError("repository " + pkg + " should not have " + v.suffix + " suffix")
+ }
+ repo := host.protocol + "://" + hm[1] + v.suffix
+ m = &vcsMatch{v, hm[1], repo}
+ }
+ }
+ }
+ if m == nil {
+ return os.NewError("cannot download: " + pkg)
+ }
+ return vcsCheckout(m.vcs, srcDir, m.prefix, m.repo, pkg)
}
// Try to detect if a "release" tag exists. If it does, update
@@ -189,7 +205,7 @@ func vcsCheckout(vcs *vcs, srcDir, pkgprefix, repo, dashpath string) os.Error {
dst := filepath.Join(srcDir, filepath.FromSlash(pkgprefix))
dir, err := os.Stat(filepath.Join(dst, vcs.metadir))
if err == nil && !dir.IsDirectory() {
- return os.ErrorString("not a directory: " + dst)
+ return os.NewError("not a directory: " + dst)
}
if err != nil {
parent, _ := filepath.Split(dst)
diff --git a/src/cmd/goinstall/main.go b/src/cmd/goinstall/main.go
index 721e719d2..bdf8469a0 100644
--- a/src/cmd/goinstall/main.go
+++ b/src/cmd/goinstall/main.go
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Experimental Go package installer; see doc.go.
-
package main
import (
@@ -11,6 +9,7 @@ import (
"exec"
"flag"
"fmt"
+ "go/build"
"go/token"
"io/ioutil"
"os"
@@ -39,7 +38,10 @@ var (
reportToDashboard = flag.Bool("dashboard", true, "report public packages at "+dashboardURL)
logPkgs = flag.Bool("log", true, "log installed packages to $GOROOT/goinstall.log for use by -a")
update = flag.Bool("u", false, "update already-downloaded packages")
+ doInstall = flag.Bool("install", true, "build and install")
clean = flag.Bool("clean", false, "clean the package directory before installing")
+ nuke = flag.Bool("nuke", false, "clean the package directory and target before installing")
+ useMake = flag.Bool("make", true, "use make to build and install")
verbose = flag.Bool("v", false, "verbose")
)
@@ -56,7 +58,7 @@ func logf(format string, args ...interface{}) {
fmt.Fprintf(os.Stderr, format, args...)
}
-func vlogf(format string, args ...interface{}) {
+func printf(format string, args ...interface{}) {
if *verbose {
logf(format, args...)
}
@@ -160,66 +162,92 @@ func install(pkg, parent string) {
fmt.Fprintf(os.Stderr, "\t%s\n", pkg)
os.Exit(2)
}
- visit[pkg] = visiting
parents[pkg] = parent
-
- vlogf("%s: visit\n", pkg)
+ visit[pkg] = visiting
+ defer func() {
+ visit[pkg] = done
+ }()
// Check whether package is local or remote.
// If remote, download or update it.
- proot, pkg, err := findPackageRoot(pkg)
+ tree, pkg, err := build.FindTree(pkg)
// Don't build the standard library.
- if err == nil && proot.goroot && isStandardPath(pkg) {
+ if err == nil && tree.Goroot && isStandardPath(pkg) {
if parent == "" {
errorf("%s: can not goinstall the standard library\n", pkg)
} else {
- vlogf("%s: skipping standard library\n", pkg)
+ printf("%s: skipping standard library\n", pkg)
}
- visit[pkg] = done
return
}
// Download remote packages if not found or forced with -u flag.
remote := isRemote(pkg)
- if remote && (err == ErrPackageNotFound || (err == nil && *update)) {
- vlogf("%s: download\n", pkg)
- err = download(pkg, proot.srcDir())
+ if remote && (err == build.ErrNotFound || (err == nil && *update)) {
+ printf("%s: download\n", pkg)
+ err = download(pkg, tree.SrcDir())
}
if err != nil {
errorf("%s: %v\n", pkg, err)
- visit[pkg] = done
return
}
- dir := filepath.Join(proot.srcDir(), pkg)
+ dir := filepath.Join(tree.SrcDir(), pkg)
// Install prerequisites.
- dirInfo, err := scanDir(dir, parent == "")
+ dirInfo, err := build.ScanDir(dir, parent == "")
if err != nil {
errorf("%s: %v\n", pkg, err)
- visit[pkg] = done
return
}
- if len(dirInfo.goFiles) == 0 {
+ if len(dirInfo.GoFiles)+len(dirInfo.CgoFiles) == 0 {
errorf("%s: package has no files\n", pkg)
- visit[pkg] = done
return
}
- for _, p := range dirInfo.imports {
+ for _, p := range dirInfo.Imports {
if p != "C" {
install(p, pkg)
}
}
+ if errors {
+ return
+ }
// Install this package.
- if !errors {
- isCmd := dirInfo.pkgName == "main"
- if err := domake(dir, pkg, proot, isCmd); err != nil {
- errorf("installing: %v\n", err)
- } else if remote && *logPkgs {
- // mark package as installed in $GOROOT/goinstall.log
- logPackage(pkg)
+ if *useMake {
+ err := domake(dir, pkg, tree, dirInfo.IsCommand())
+ if err != nil {
+ errorf("%s: install: %v\n", pkg, err)
+ return
+ }
+ } else {
+ script, err := build.Build(tree, pkg, dirInfo)
+ if err != nil {
+ errorf("%s: install: %v\n", pkg, err)
+ return
}
+ if *nuke {
+ printf("%s: nuke\n", pkg)
+ script.Nuke()
+ } else if *clean {
+ printf("%s: clean\n", pkg)
+ script.Clean()
+ }
+ if *doInstall {
+ if script.Stale() {
+ printf("%s: install\n", pkg)
+ if err := script.Run(); err != nil {
+ errorf("%s: install: %v\n", pkg, err)
+ return
+ }
+ } else {
+ printf("%s: up-to-date\n", pkg)
+ }
+ }
+ }
+ if remote {
+ // mark package as installed in $GOROOT/goinstall.log
+ logPackage(pkg)
}
- visit[pkg] = done
+ return
}
@@ -249,7 +277,7 @@ func genRun(dir string, stdin []byte, arg []string, quiet bool) os.Error {
cmd := exec.Command(arg[0], arg[1:]...)
cmd.Stdin = bytes.NewBuffer(stdin)
cmd.Dir = dir
- vlogf("%s: %s %s\n", dir, cmd.Path, strings.Join(arg[1:], " "))
+ printf("%s: %s %s\n", dir, cmd.Path, strings.Join(arg[1:], " "))
out, err := cmd.CombinedOutput()
if err != nil {
if !quiet || *verbose {
@@ -260,7 +288,7 @@ func genRun(dir string, stdin []byte, arg []string, quiet bool) os.Error {
os.Stderr.Write(out)
fmt.Fprintf(os.Stderr, "--- %s\n", err)
}
- return os.ErrorString("running " + arg[0] + ": " + err.String())
+ return os.NewError("running " + arg[0] + ": " + err.String())
}
return nil
}
diff --git a/src/cmd/goinstall/make.go b/src/cmd/goinstall/make.go
index 0c44481d7..0fd9b02a8 100644
--- a/src/cmd/goinstall/make.go
+++ b/src/cmd/goinstall/make.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors. All rights reserved.
+// 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.
@@ -8,21 +8,25 @@ package main
import (
"bytes"
+ "go/build"
"os"
"path/filepath"
+ "strings"
"template"
)
// domake builds the package in dir.
// domake generates a standard Makefile and passes it
// to make on standard input.
-func domake(dir, pkg string, root *pkgroot, isCmd bool) (err os.Error) {
- makefile, err := makeMakefile(dir, pkg, root, isCmd)
+func domake(dir, pkg string, tree *build.Tree, isCmd bool) (err os.Error) {
+ makefile, err := makeMakefile(dir, pkg, tree, isCmd)
if err != nil {
return err
}
cmd := []string{"bash", "gomake", "-f-"}
- if *clean {
+ if *nuke {
+ cmd = append(cmd, "nuke")
+ } else if *clean {
cmd = append(cmd, "clean")
}
cmd = append(cmd, "install")
@@ -32,46 +36,46 @@ func domake(dir, pkg string, root *pkgroot, isCmd bool) (err os.Error) {
// makeMakefile computes the standard Makefile for the directory dir
// installing as package pkg. It includes all *.go files in the directory
// except those in package main and those ending in _test.go.
-func makeMakefile(dir, pkg string, root *pkgroot, isCmd bool) ([]byte, os.Error) {
+func makeMakefile(dir, pkg string, tree *build.Tree, isCmd bool) ([]byte, os.Error) {
if !safeName(pkg) {
- return nil, os.ErrorString("unsafe name: " + pkg)
+ return nil, os.NewError("unsafe name: " + pkg)
}
targ := pkg
- targDir := root.pkgDir()
+ targDir := tree.PkgDir()
if isCmd {
// use the last part of the package name for targ
_, targ = filepath.Split(pkg)
- targDir = root.binDir()
+ targDir = tree.BinDir()
}
- dirInfo, err := scanDir(dir, isCmd)
+ dirInfo, err := build.ScanDir(dir, isCmd)
if err != nil {
return nil, err
}
- cgoFiles := dirInfo.cgoFiles
+ cgoFiles := dirInfo.CgoFiles
isCgo := make(map[string]bool, len(cgoFiles))
for _, file := range cgoFiles {
if !safeName(file) {
- return nil, os.ErrorString("bad name: " + file)
+ return nil, os.NewError("bad name: " + file)
}
isCgo[file] = true
}
- goFiles := make([]string, 0, len(dirInfo.goFiles))
- for _, file := range dirInfo.goFiles {
+ goFiles := make([]string, 0, len(dirInfo.GoFiles))
+ for _, file := range dirInfo.GoFiles {
if !safeName(file) {
- return nil, os.ErrorString("unsafe name: " + file)
+ return nil, os.NewError("unsafe name: " + file)
}
if !isCgo[file] {
goFiles = append(goFiles, file)
}
}
- oFiles := make([]string, 0, len(dirInfo.cFiles)+len(dirInfo.sFiles))
- cgoOFiles := make([]string, 0, len(dirInfo.cFiles))
- for _, file := range dirInfo.cFiles {
+ oFiles := make([]string, 0, len(dirInfo.CFiles)+len(dirInfo.SFiles))
+ cgoOFiles := make([]string, 0, len(dirInfo.CFiles))
+ for _, file := range dirInfo.CFiles {
if !safeName(file) {
- return nil, os.ErrorString("unsafe name: " + file)
+ return nil, os.NewError("unsafe name: " + file)
}
// When cgo is in use, C files are compiled with gcc,
// otherwise they're compiled with gc.
@@ -82,13 +86,18 @@ func makeMakefile(dir, pkg string, root *pkgroot, isCmd bool) ([]byte, os.Error)
}
}
- for _, file := range dirInfo.sFiles {
+ for _, file := range dirInfo.SFiles {
if !safeName(file) {
- return nil, os.ErrorString("unsafe name: " + file)
+ return nil, os.NewError("unsafe name: " + file)
}
oFiles = append(oFiles, file[:len(file)-2]+".$O")
}
+ var imports []string
+ for _, t := range build.Path {
+ imports = append(imports, t.PkgDir())
+ }
+
var buf bytes.Buffer
md := makedata{targ, targDir, "pkg", goFiles, oFiles, cgoFiles, cgoOFiles, imports}
if isCmd {
@@ -106,6 +115,9 @@ func safeName(s string) bool {
if s == "" {
return false
}
+ if strings.Contains(s, "..") {
+ return false
+ }
for i := 0; i < len(s); i++ {
if c := s[i]; c < 0x80 && bytes.IndexByte(safeBytes, c) < 0 {
return false
@@ -134,28 +146,28 @@ TARGDIR={TargDir}
{.section GoFiles}
GOFILES=\
-{.repeated section GoFiles}
+{.repeated section @}
{@}\
{.end}
{.end}
{.section OFiles}
OFILES=\
-{.repeated section OFiles}
+{.repeated section @}
{@}\
{.end}
{.end}
{.section CgoFiles}
CGOFILES=\
-{.repeated section CgoFiles}
+{.repeated section @}
{@}\
{.end}
{.end}
{.section CgoOFiles}
CGO_OFILES=\
-{.repeated section CgoOFiles}
+{.repeated section @}
{@}\
{.end}
diff --git a/src/cmd/goinstall/parse.go b/src/cmd/goinstall/parse.go
deleted file mode 100644
index a4bb761f2..000000000
--- a/src/cmd/goinstall/parse.go
+++ /dev/null
@@ -1,172 +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.
-
-// Wrappers for Go parser.
-
-package main
-
-import (
- "go/ast"
- "go/parser"
- "log"
- "os"
- "path/filepath"
- "strconv"
- "strings"
- "runtime"
-)
-
-
-type dirInfo struct {
- goFiles []string // .go files within dir (including cgoFiles)
- cgoFiles []string // .go files that import "C"
- cFiles []string // .c files within dir
- sFiles []string // .s files within dir
- imports []string // All packages imported by goFiles
- pkgName string // Name of package within dir
-}
-
-// scanDir returns a structure with details about the Go content found
-// in the given directory. The list of files will NOT contain the
-// following entries:
-//
-// - Files in package main (unless allowMain is true)
-// - Files ending in _test.go
-// - Files starting with _ (temporary)
-// - Files containing .cgo in their names
-//
-// The imports map keys are package paths imported by listed Go files,
-// and the values are the Go files importing the respective package paths.
-func scanDir(dir string, allowMain bool) (info *dirInfo, err os.Error) {
- f, err := os.Open(dir)
- if err != nil {
- return nil, err
- }
- dirs, err := f.Readdir(-1)
- f.Close()
- if err != nil {
- return nil, err
- }
-
- goFiles := make([]string, 0, len(dirs))
- cgoFiles := make([]string, 0, len(dirs))
- cFiles := make([]string, 0, len(dirs))
- sFiles := make([]string, 0, len(dirs))
- importsm := make(map[string]bool)
- pkgName := ""
- for i := range dirs {
- d := &dirs[i]
- if strings.HasPrefix(d.Name, "_") || strings.Index(d.Name, ".cgo") != -1 {
- continue
- }
- if !goodOSArch(d.Name) {
- continue
- }
-
- switch filepath.Ext(d.Name) {
- case ".go":
- if strings.HasSuffix(d.Name, "_test.go") {
- continue
- }
- case ".c":
- cFiles = append(cFiles, d.Name)
- continue
- case ".s":
- sFiles = append(sFiles, d.Name)
- continue
- default:
- continue
- }
-
- filename := filepath.Join(dir, d.Name)
- pf, err := parser.ParseFile(fset, filename, nil, parser.ImportsOnly)
- if err != nil {
- return nil, err
- }
- s := string(pf.Name.Name)
- if s == "main" && !allowMain {
- continue
- }
- if s == "documentation" {
- continue
- }
- if pkgName == "" {
- pkgName = s
- } else if pkgName != s {
- // Only if all files in the directory are in package main
- // do we return pkgName=="main".
- // A mix of main and another package reverts
- // to the original (allowMain=false) behaviour.
- if s == "main" || pkgName == "main" {
- return scanDir(dir, false)
- }
- return nil, os.ErrorString("multiple package names in " + dir)
- }
- goFiles = append(goFiles, d.Name)
- for _, decl := range pf.Decls {
- for _, spec := range decl.(*ast.GenDecl).Specs {
- quoted := string(spec.(*ast.ImportSpec).Path.Value)
- unquoted, err := strconv.Unquote(quoted)
- if err != nil {
- log.Panicf("%s: parser returned invalid quoted string: <%s>", filename, quoted)
- }
- importsm[unquoted] = true
- if unquoted == "C" {
- cgoFiles = append(cgoFiles, d.Name)
- }
- }
- }
- }
- imports := make([]string, len(importsm))
- i := 0
- for p := range importsm {
- imports[i] = p
- i++
- }
- return &dirInfo{goFiles, cgoFiles, cFiles, sFiles, imports, pkgName}, nil
-}
-
-// goodOSArch returns false if the filename contains a $GOOS or $GOARCH
-// suffix which does not match the current system.
-// The recognized filename formats are:
-//
-// name_$(GOOS).*
-// name_$(GOARCH).*
-// name_$(GOOS)_$(GOARCH).*
-//
-func goodOSArch(filename string) bool {
- if dot := strings.Index(filename, "."); dot != -1 {
- filename = filename[:dot]
- }
- l := strings.Split(filename, "_", -1)
- n := len(l)
- if n == 0 {
- return true
- }
- if good, known := goodOS[l[n-1]]; known {
- return good
- }
- if good, known := goodArch[l[n-1]]; known {
- if !good || n < 2 {
- return false
- }
- good, known = goodOS[l[n-2]]
- return good || !known
- }
- return true
-}
-
-var goodOS = make(map[string]bool)
-var goodArch = make(map[string]bool)
-
-func init() {
- goodOS = make(map[string]bool)
- goodArch = make(map[string]bool)
- for _, v := range strings.Fields(goosList) {
- goodOS[v] = v == runtime.GOOS
- }
- for _, v := range strings.Fields(goarchList) {
- goodArch[v] = v == runtime.GOARCH
- }
-}
diff --git a/src/cmd/goinstall/path.go b/src/cmd/goinstall/path.go
deleted file mode 100644
index b8c392931..000000000
--- a/src/cmd/goinstall/path.go
+++ /dev/null
@@ -1,149 +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 main
-
-import (
- "fmt"
- "log"
- "os"
- "path/filepath"
- "runtime"
- "strings"
-)
-
-var (
- gopath []*pkgroot
- imports []string
- defaultRoot *pkgroot // default root for remote packages
-)
-
-// set up gopath: parse and validate GOROOT and GOPATH variables
-func init() {
- root := runtime.GOROOT()
- p, err := newPkgroot(root)
- if err != nil {
- log.Fatalf("Invalid GOROOT %q: %v", root, err)
- }
- p.goroot = true
- gopath = []*pkgroot{p}
-
- for _, p := range filepath.SplitList(os.Getenv("GOPATH")) {
- if p == "" {
- continue
- }
- r, err := newPkgroot(p)
- if err != nil {
- log.Printf("Invalid GOPATH %q: %v", p, err)
- continue
- }
- gopath = append(gopath, r)
- imports = append(imports, r.pkgDir())
-
- // select first GOPATH entry as default
- if defaultRoot == nil {
- defaultRoot = r
- }
- }
-
- // use GOROOT if no valid GOPATH specified
- if defaultRoot == nil {
- defaultRoot = gopath[0]
- }
-}
-
-type pkgroot struct {
- path string
- goroot bool // TODO(adg): remove this once Go tree re-organized
-}
-
-func newPkgroot(p string) (*pkgroot, os.Error) {
- if !filepath.IsAbs(p) {
- return nil, os.NewError("must be absolute")
- }
- ep, err := filepath.EvalSymlinks(p)
- if err != nil {
- return nil, err
- }
- return &pkgroot{path: ep}, nil
-}
-
-func (r *pkgroot) srcDir() string {
- if r.goroot {
- return filepath.Join(r.path, "src", "pkg")
- }
- return filepath.Join(r.path, "src")
-}
-
-func (r *pkgroot) pkgDir() string {
- goos, goarch := runtime.GOOS, runtime.GOARCH
- if e := os.Getenv("GOOS"); e != "" {
- goos = e
- }
- if e := os.Getenv("GOARCH"); e != "" {
- goarch = e
- }
- return filepath.Join(r.path, "pkg", goos+"_"+goarch)
-}
-
-func (r *pkgroot) binDir() string {
- return filepath.Join(r.path, "bin")
-}
-
-func (r *pkgroot) hasSrcDir(name string) bool {
- fi, err := os.Stat(filepath.Join(r.srcDir(), name))
- if err != nil {
- return false
- }
- return fi.IsDirectory()
-}
-
-func (r *pkgroot) hasPkg(name string) bool {
- fi, err := os.Stat(filepath.Join(r.pkgDir(), name+".a"))
- if err != nil {
- return false
- }
- return fi.IsRegular()
- // TODO(adg): check object version is consistent
-}
-
-
-var ErrPackageNotFound = os.NewError("package could not be found locally")
-
-// findPackageRoot takes an import or filesystem path and returns the
-// root where the package source should be and the package import path.
-func findPackageRoot(path string) (root *pkgroot, pkg string, err os.Error) {
- if isLocalPath(path) {
- if path, err = filepath.Abs(path); err != nil {
- return
- }
- for _, r := range gopath {
- rpath := r.srcDir() + string(filepath.Separator)
- if !strings.HasPrefix(path, rpath) {
- continue
- }
- root = r
- pkg = path[len(rpath):]
- return
- }
- err = fmt.Errorf("path %q not inside a GOPATH", path)
- return
- }
- root = defaultRoot
- pkg = path
- for _, r := range gopath {
- if r.hasSrcDir(path) {
- root = r
- return
- }
- }
- err = ErrPackageNotFound
- return
-}
-
-// Is this a local path? /foo ./foo ../foo . ..
-func isLocalPath(s string) bool {
- const sep = string(filepath.Separator)
- return strings.HasPrefix(s, sep) || strings.HasPrefix(s, "."+sep) || strings.HasPrefix(s, ".."+sep) || s == "." || s == ".."
-}
diff --git a/src/cmd/goinstall/syslist_test.go b/src/cmd/goinstall/syslist_test.go
deleted file mode 100644
index 795cd293a..000000000
--- a/src/cmd/goinstall/syslist_test.go
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-package main
-
-import (
- "runtime"
- "testing"
-)
-
-var (
- thisOS = runtime.GOOS
- thisArch = runtime.GOARCH
- otherOS = anotherOS()
- otherArch = anotherArch()
-)
-
-func anotherOS() string {
- if thisOS != "darwin" {
- return "darwin"
- }
- return "linux"
-}
-
-func anotherArch() string {
- if thisArch != "amd64" {
- return "amd64"
- }
- return "386"
-}
-
-type GoodFileTest struct {
- name string
- result bool
-}
-
-var tests = []GoodFileTest{
- {"file.go", true},
- {"file.c", true},
- {"file_foo.go", true},
- {"file_" + thisArch + ".go", true},
- {"file_" + otherArch + ".go", false},
- {"file_" + thisOS + ".go", true},
- {"file_" + otherOS + ".go", false},
- {"file_" + thisOS + "_" + thisArch + ".go", true},
- {"file_" + otherOS + "_" + thisArch + ".go", false},
- {"file_" + thisOS + "_" + otherArch + ".go", false},
- {"file_" + otherOS + "_" + otherArch + ".go", false},
- {"file_foo_" + thisArch + ".go", true},
- {"file_foo_" + otherArch + ".go", false},
- {"file_" + thisOS + ".c", true},
- {"file_" + otherOS + ".c", false},
-}
-
-func TestGoodOSArch(t *testing.T) {
- for _, test := range tests {
- if goodOSArch(test.name) != test.result {
- t.Fatalf("goodOSArch(%q) != %v", test.name, test.result)
- }
- }
-}
diff --git a/src/cmd/gopack/Makefile b/src/cmd/gopack/Makefile
index 859809562..91a8ac2df 100644
--- a/src/cmd/gopack/Makefile
+++ b/src/cmd/gopack/Makefile
@@ -9,7 +9,4 @@ TARG=gopack
OFILES=\
ar.$O\
-LIB=\
- ../../../lib/libmach.a\
-
include ../../Make.ccmd
diff --git a/src/cmd/gotype/gotype.go b/src/cmd/gotype/gotype.go
index b6a23ae5f..501ead443 100644
--- a/src/cmd/gotype/gotype.go
+++ b/src/cmd/gotype/gotype.go
@@ -114,7 +114,7 @@ func parseFiles(fset *token.FileSet, filenames []string) (files map[string]*ast.
}
if file := parse(fset, filename, src); file != nil {
if files[filename] != nil {
- report(os.ErrorString(fmt.Sprintf("%q: duplicate file", filename)))
+ report(os.NewError(fmt.Sprintf("%q: duplicate file", filename)))
continue
}
files[filename] = file
diff --git a/src/cmd/hgpatch/main.go b/src/cmd/hgpatch/main.go
index 8ee3422e2..1f3e5e736 100644
--- a/src/cmd/hgpatch/main.go
+++ b/src/cmd/hgpatch/main.go
@@ -329,15 +329,14 @@ var lookPathCache = make(map[string]string)
// It provides input on standard input to the command.
func run(argv []string, input []byte) (out string, err os.Error) {
if len(argv) < 1 {
- err = os.EINVAL
- goto Error
+ return "", &runError{dup(argv), os.EINVAL}
}
prog, ok := lookPathCache[argv[0]]
if !ok {
prog, err = exec.LookPath(argv[0])
if err != nil {
- goto Error
+ return "", &runError{dup(argv), err}
}
lookPathCache[argv[0]] = prog
}
@@ -347,13 +346,10 @@ func run(argv []string, input []byte) (out string, err os.Error) {
cmd.Stdin = bytes.NewBuffer(input)
}
bs, err := cmd.CombinedOutput()
- if err == nil {
- return string(bs), nil
+ if err != nil {
+ return "", &runError{dup(argv), err}
}
-
-Error:
- err = &runError{dup(argv), err}
- return
+ return string(bs), nil
}
// A runError represents an error that occurred while running a command.
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c
index 3f3faade0..bdad58ff9 100644
--- a/src/cmd/ld/data.c
+++ b/src/cmd/ld/data.c
@@ -249,7 +249,7 @@ dynrelocsym(Sym *s)
return;
for(r=s->r; r<s->r+s->nr; r++) {
targ = r->sym;
- if(r->sym->plt == -2) { // make dynimport JMP table for PE object files.
+ if(r->sym->plt == -2 && r->sym->got != -2) { // make dynimport JMP table for PE object files.
targ->plt = rel->size;
r->sym = rel;
r->add = targ->plt;
@@ -278,6 +278,10 @@ dynreloc(void)
{
Sym *s;
+ // -d supresses dynamic loader format, so we may as well not
+ // compute these sections or mark their symbols as reachable.
+ if(debug['d'] && HEADTYPE != Hwindows)
+ return;
if(debug['v'])
Bprint(&bso, "%5.2f reloc\n", cputime());
Bflush(&bso);
@@ -482,13 +486,13 @@ codeblk(int32 addr, int32 size)
q = sym->p;
while(n >= 16) {
- Bprint(&bso, "%.6ux\t%-20.16I\n", addr, q);
+ Bprint(&bso, "%.6ux\t%-20.16I\n", addr, q);
addr += 16;
q += 16;
n -= 16;
}
if(n > 0)
- Bprint(&bso, "%.6ux\t%-20.*I\n", addr, n, q);
+ Bprint(&bso, "%.6ux\t%-20.*I\n", addr, (int)n, q);
addr += n;
continue;
}
@@ -502,7 +506,7 @@ codeblk(int32 addr, int32 size)
Bprint(&bso, "%.6ux\t", p->pc);
q = sym->p + p->pc - sym->value;
n = epc - p->pc;
- Bprint(&bso, "%-20.*I | %P\n", n, q, p);
+ Bprint(&bso, "%-20.*I | %P\n", (int)n, q, p);
addr += n;
}
}
@@ -543,7 +547,7 @@ datblk(int32 addr, int32 size)
Bprint(&bso, "%-20s %.8ux| 00 ...\n", "(pre-pad)", addr);
addr = sym->value;
}
- Bprint(&bso, "%-20s %.8ux|", sym->name, addr);
+ Bprint(&bso, "%-20s %.8ux|", sym->name, (uint)addr);
p = sym->p;
ep = p + sym->np;
while(p < ep)
@@ -555,8 +559,8 @@ datblk(int32 addr, int32 size)
}
if(addr < eaddr)
- Bprint(&bso, "%-20s %.8ux| 00 ...\n", "(post-pad)", addr);
- Bprint(&bso, "%-20s %.8ux|\n", "", eaddr);
+ Bprint(&bso, "%-20s %.8ux| 00 ...\n", "(post-pad)", (uint)addr);
+ Bprint(&bso, "%-20s %.8ux|\n", "", (uint)eaddr);
}
void
@@ -781,7 +785,7 @@ dodata(void)
*/
/* read-only data */
- sect = addsection(&segtext, ".rodata", 06);
+ sect = addsection(&segtext, ".rodata", 04);
sect->vaddr = 0;
datsize = 0;
s = datap;
@@ -808,9 +812,9 @@ dodata(void)
t = rnd(t, PtrSize);
else if(t > 2)
t = rnd(t, 4);
- if(t & 1)
+ if(t & 1) {
;
- else if(t & 2)
+ } else if(t & 2)
datsize = rnd(datsize, 2);
else if(t & 4)
datsize = rnd(datsize, 4);
@@ -834,9 +838,9 @@ dodata(void)
t = rnd(t, PtrSize);
else if(t > 2)
t = rnd(t, 4);
- if(t & 1)
+ if(t & 1) {
;
- else if(t & 2)
+ } else if(t & 2)
datsize = rnd(datsize, 2);
else if(t & 4)
datsize = rnd(datsize, 4);
diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c
index 1721def67..1c10dc796 100644
--- a/src/cmd/ld/dwarf.c
+++ b/src/cmd/ld/dwarf.c
@@ -1804,7 +1804,7 @@ mkvarname(char* name, int da)
// flush previous compilation unit.
static void
-flushunit(DWDie *dwinfo, vlong pc, vlong unitstart)
+flushunit(DWDie *dwinfo, vlong pc, vlong unitstart, int32 header_length)
{
vlong here;
@@ -1820,7 +1820,9 @@ flushunit(DWDie *dwinfo, vlong pc, vlong unitstart)
here = cpos();
seek(cout, unitstart, 0);
- LPUT(here - unitstart - sizeof(int32));
+ LPUT(here - unitstart - sizeof(int32)); // unit_length
+ WPUT(3); // dwarf version
+ LPUT(header_length); // header length starting here
cflush();
seek(cout, here, 0);
}
@@ -1832,7 +1834,7 @@ writelines(void)
Prog *q;
Sym *s;
Auto *a;
- vlong unitstart, offs;
+ vlong unitstart, headerend, offs;
vlong pc, epc, lc, llc, lline;
int currfile;
int i, lang, da, dt;
@@ -1842,6 +1844,7 @@ writelines(void)
char *n, *nn;
unitstart = -1;
+ headerend = -1;
pc = 0;
epc = 0;
lc = 1;
@@ -1859,7 +1862,7 @@ writelines(void)
// we're entering a new compilation unit
if (inithist(s->autom)) {
- flushunit(dwinfo, epc, unitstart);
+ flushunit(dwinfo, epc, unitstart, headerend - unitstart - 10);
unitstart = cpos();
if(debug['v'] > 1) {
@@ -1880,10 +1883,10 @@ writelines(void)
// Write .debug_line Line Number Program Header (sec 6.2.4)
// Fields marked with (*) must be changed for 64-bit dwarf
- LPUT(0); // unit_length (*), will be filled in later.
+ LPUT(0); // unit_length (*), will be filled in by flushunit.
WPUT(3); // dwarf version (appendix F)
- LPUT(11); // header_length (*), starting here.
-
+ LPUT(0); // header_length (*), filled in by flushunit.
+ // cpos == unitstart + 4 + 2 + 4
cput(1); // minimum_instruction_length
cput(1); // default_is_stmt
cput(LINE_BASE); // line_base
@@ -1894,17 +1897,15 @@ writelines(void)
cput(1); // standard_opcode_lengths[3]
cput(1); // standard_opcode_lengths[4]
cput(0); // include_directories (empty)
- cput(0); // file_names (empty) (emitted by DW_LNE's below)
- // header_length ends here.
for (i=1; i < histfilesize; i++) {
- cput(0); // start extended opcode
- uleb128put(1 + strlen(histfile[i]) + 4);
- cput(DW_LNE_define_file);
strnput(histfile[i], strlen(histfile[i]) + 4);
// 4 zeros: the string termination + 3 fields.
}
+ cput(0); // terminate file_names.
+ headerend = cpos();
+
pc = s->text->pc;
epc = pc;
currfile = 1;
@@ -2009,7 +2010,7 @@ writelines(void)
dwfunc->hash = nil;
}
- flushunit(dwinfo, epc, unitstart);
+ flushunit(dwinfo, epc, unitstart, headerend - unitstart - 10);
linesize = cpos() - lineo;
}
diff --git a/src/cmd/ld/elf.h b/src/cmd/ld/elf.h
index d1370d28b..c63df2241 100644
--- a/src/cmd/ld/elf.h
+++ b/src/cmd/ld/elf.h
@@ -110,7 +110,6 @@ typedef struct {
#define ELFOSABI_OPENVMS 13 /* Open VMS */
#define ELFOSABI_NSK 14 /* HP Non-Stop Kernel */
#define ELFOSABI_ARM 97 /* ARM */
-#define ELFOSABI_NACL 123 /* Native Client */
#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */
#define ELFOSABI_SYSV ELFOSABI_NONE /* symbol used in old spec */
@@ -262,8 +261,8 @@ typedef struct {
/* Values for d_tag. */
#define DT_NULL 0 /* Terminating entry. */
-#define DT_NEEDED 1 /* String table offset of a needed shared
- library. */
+/* String table offset of a needed shared library. */
+#define DT_NEEDED 1
#define DT_PLTRELSZ 2 /* Total size in bytes of PLT relocations. */
#define DT_PLTGOT 3 /* Processor-dependent address. */
#define DT_HASH 4 /* Address of symbol hash table. */
@@ -276,8 +275,8 @@ typedef struct {
#define DT_SYMENT 11 /* Size of each symbol table entry. */
#define DT_INIT 12 /* Address of initialization function. */
#define DT_FINI 13 /* Address of finalization function. */
-#define DT_SONAME 14 /* String table offset of shared object
- name. */
+/* String table offset of shared object name. */
+#define DT_SONAME 14
#define DT_RPATH 15 /* String table offset of library path. [sup] */
#define DT_SYMBOLIC 16 /* Indicates "symbolic" linking. [sup] */
#define DT_REL 17 /* Address of ElfNN_Rel relocations. */
@@ -285,30 +284,29 @@ typedef struct {
#define DT_RELENT 19 /* Size of each ElfNN_Rel relocation. */
#define DT_PLTREL 20 /* Type of relocation used for PLT. */
#define DT_DEBUG 21 /* Reserved (not used). */
-#define DT_TEXTREL 22 /* Indicates there may be relocations in
- non-writable segments. [sup] */
+/* Indicates there may be relocations in non-writable segments. [sup] */
+#define DT_TEXTREL 22
#define DT_JMPREL 23 /* Address of PLT relocations. */
#define DT_BIND_NOW 24 /* [sup] */
-#define DT_INIT_ARRAY 25 /* Address of the array of pointers to
- initialization functions */
-#define DT_FINI_ARRAY 26 /* Address of the array of pointers to
- termination functions */
-#define DT_INIT_ARRAYSZ 27 /* Size in bytes of the array of
- initialization functions. */
-#define DT_FINI_ARRAYSZ 28 /* Size in bytes of the array of
- terminationfunctions. */
-#define DT_RUNPATH 29 /* String table offset of a null-terminated
- library search path string. */
+/* Address of the array of pointers to initialization functions */
+#define DT_INIT_ARRAY 25
+/* Address of the array of pointers to termination functions */
+#define DT_FINI_ARRAY 26
+/* Size in bytes of the array of initialization functions. */
+#define DT_INIT_ARRAYSZ 27
+/* Size in bytes of the array of terminationfunctions. */
+#define DT_FINI_ARRAYSZ 28
+/* String table offset of a null-terminated library search path string. */
+#define DT_RUNPATH 29
#define DT_FLAGS 30 /* Object specific flag values. */
-#define DT_ENCODING 32 /* Values greater than or equal to DT_ENCODING
- and less than DT_LOOS follow the rules for
- the interpretation of the d_un union
- as follows: even == 'd_ptr', even == 'd_val'
- or none */
-#define DT_PREINIT_ARRAY 32 /* Address of the array of pointers to
- pre-initialization functions. */
-#define DT_PREINIT_ARRAYSZ 33 /* Size in bytes of the array of
- pre-initialization functions. */
+/* Values greater than or equal to DT_ENCODING and less than
+ DT_LOOS follow the rules for the interpretation of the d_un
+ union as follows: even == 'd_ptr', even == 'd_val' or none */
+#define DT_ENCODING 32
+/* Address of the array of pointers to pre-initialization functions. */
+#define DT_PREINIT_ARRAY 32
+/* Size in bytes of the array of pre-initialization functions. */
+#define DT_PREINIT_ARRAYSZ 33
#define DT_LOOS 0x6000000d /* First OS-specific */
#define DT_HIOS 0x6ffff000 /* Last OS-specific */
#define DT_LOPROC 0x70000000 /* First processor-specific type. */
@@ -319,19 +317,19 @@ typedef struct {
#define DT_VERSYM 0x6ffffff0
/* Values for DT_FLAGS */
-#define DF_ORIGIN 0x0001 /* Indicates that the object being loaded may
- make reference to the $ORIGIN substitution
- string */
+/* Indicates that the object being loaded may make reference to
+ the $ORIGIN substitution string */
+#define DF_ORIGIN 0x0001
#define DF_SYMBOLIC 0x0002 /* Indicates "symbolic" linking. */
-#define DF_TEXTREL 0x0004 /* Indicates there may be relocations in
- non-writable segments. */
-#define DF_BIND_NOW 0x0008 /* Indicates that the dynamic linker should
- process all relocations for the object
- containing this entry before transferring
- control to the program. */
-#define DF_STATIC_TLS 0x0010 /* Indicates that the shared object or
- executable contains code using a static
- thread-local storage scheme. */
+/* Indicates there may be relocations in non-writable segments. */
+#define DF_TEXTREL 0x0004
+/* Indicates that the dynamic linker should process all
+ relocations for the object containing this entry before
+ transferring control to the program. */
+#define DF_BIND_NOW 0x0008
+/* Indicates that the shared object or executable contains code
+ using a static thread-local storage scheme. */
+#define DF_STATIC_TLS 0x0010
/* Values for n_type. Used in core files. */
#define NT_PRSTATUS 1 /* Process status. */
diff --git a/src/cmd/ld/ldelf.c b/src/cmd/ld/ldelf.c
index d61020e49..8334e988e 100644
--- a/src/cmd/ld/ldelf.c
+++ b/src/cmd/ld/ldelf.c
@@ -328,15 +328,16 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
Reloc *r, *rp;
Sym *s;
+ USED(pkg);
if(debug['v'])
Bprint(&bso, "%5.2f ldelf %s\n", cputime(), pn);
version++;
base = Boffset(f);
- if(Bread(f, &hdrbuf, sizeof hdrbuf) != sizeof hdrbuf)
+ if(Bread(f, hdrbuf, sizeof hdrbuf) != sizeof hdrbuf)
goto bad;
- hdr = (ElfHdrBytes*)&hdrbuf;
+ hdr = (ElfHdrBytes*)hdrbuf;
if(memcmp(hdr->ident, ElfMagic, 4) != 0)
goto bad;
switch(hdr->ident[5]) {
@@ -518,7 +519,7 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
name = smprint("%s(%s)", pn, sect->name);
s = lookup(name, version);
free(name);
- switch(sect->flags&(ElfSectFlagAlloc|ElfSectFlagWrite|ElfSectFlagExec)) {
+ switch((int)sect->flags&(ElfSectFlagAlloc|ElfSectFlagWrite|ElfSectFlagExec)) {
default:
werrstr("unexpected flags for ELF section %s", sect->name);
goto bad;
diff --git a/src/cmd/ld/ldmacho.c b/src/cmd/ld/ldmacho.c
index bbb21d51a..abbc3b3cd 100644
--- a/src/cmd/ld/ldmacho.c
+++ b/src/cmd/ld/ldmacho.c
@@ -440,6 +440,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
Reloc *r, *rp;
char *name;
+ USED(pkg);
version++;
base = Boffset(f);
if(Bread(f, hdr, sizeof hdr) != sizeof hdr)
diff --git a/src/cmd/ld/ldpe.c b/src/cmd/ld/ldpe.c
index d6aa267c4..98c866fee 100644
--- a/src/cmd/ld/ldpe.c
+++ b/src/cmd/ld/ldpe.c
@@ -125,10 +125,13 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
Sym *s;
Reloc *r, *rp;
PeSym *sym;
-
+
+ USED(len);
+ USED(pkg);
if(debug['v'])
Bprint(&bso, "%5.2f ldpe %s\n", cputime(), pn);
+ sect = nil;
version++;
base = Boffset(f);
@@ -304,6 +307,8 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
diag("%s: %s sectnum <0!", pn, s->name, sym->sectnum);
}
+ if(sect == nil)
+ return;
s->sub = sect->sym->sub;
sect->sym->sub = s;
s->type = sect->sym->type | SSUB;
@@ -366,12 +371,11 @@ readsym(PeObj *obj, int i, PeSym **y)
sym = &obj->pesym[i];
*y = sym;
- s = nil;
name = sym->name;
if(sym->sclass == IMAGE_SYM_CLASS_STATIC && sym->value == 0) // section
name = obj->sect[sym->sectnum-1].sym->name;
- if(strncmp(sym->name, "__imp__", 6) == 0)
+ if(strncmp(sym->name, "__imp__", 7) == 0)
name = &sym->name[7]; // __imp__Name => Name
else if(sym->name[0] == '_')
name = &sym->name[1]; // _Name => Name
@@ -403,6 +407,8 @@ readsym(PeObj *obj, int i, PeSym **y)
if(s != nil && s->type == 0 && !(sym->sclass == IMAGE_SYM_CLASS_STATIC && sym->value == 0))
s->type = SXREF;
+ if(strncmp(sym->name, "__imp__", 7) == 0)
+ s->got = -2; // flag for __imp__
sym->sym = s;
return 0;
diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h
index dfd18fbff..463713143 100644
--- a/src/cmd/ld/lib.h
+++ b/src/cmd/ld/lib.h
@@ -260,10 +260,8 @@ enum {
Hipaq, // ipaq
Hdarwin, // Apple Mach-O
Hlinux, // Linux ELF
- Hnacl, // Google Native Client
Hfreebsd, // FreeBSD ELF
Hwindows, // MS Windows PE
- Htiny // tiny (os image)
};
typedef struct Header Header;
diff --git a/src/cmd/ld/pe.c b/src/cmd/ld/pe.c
index 91e15d343..9ac0a50d8 100644
--- a/src/cmd/ld/pe.c
+++ b/src/cmd/ld/pe.c
@@ -5,8 +5,6 @@
// PE (Portable Executable) file writing
// http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx
-#include <time.h>
-
#include "l.h"
#include "../ld/lib.h"
#include "../ld/pe.h"
@@ -150,7 +148,7 @@ pewrite(void)
ewrite(cout, &oh64, sizeof oh64);
else
ewrite(cout, &oh, sizeof oh);
- ewrite(cout, &sh, nsect * sizeof sh[0]);
+ ewrite(cout, sh, nsect * sizeof sh[0]);
}
static void
@@ -175,7 +173,7 @@ initdynimport(void)
Sym *s, *dynamic;
dr = nil;
-
+ m = nil;
for(s = allsym; s != S; s = s->allsym) {
if(!s->reachable || !s->dynimpname || s->dynexport)
continue;
diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c
index e3093b2aa..c66eca148 100644
--- a/src/cmd/ld/symtab.c
+++ b/src/cmd/ld/symtab.c
@@ -90,6 +90,7 @@ putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
{
int bind, type, shndx, off;
+ USED(go);
switch(t) {
default:
return;
@@ -127,6 +128,10 @@ putplan9sym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
{
int i;
+ USED(go);
+ USED(ver);
+ USED(size);
+ USED(x);
switch(t) {
case 'T':
case 'L':
@@ -252,6 +257,7 @@ putsymb(Sym *s, char *name, int t, vlong v, vlong size, int ver, Sym *typ)
int i, f, l;
Reloc *rel;
+ USED(size);
if(t == 'f')
name++;
l = 4;
@@ -280,7 +286,6 @@ putsymb(Sym *s, char *name, int t, vlong v, vlong size, int ver, Sym *typ)
}
scput(0);
scput(0);
- i++;
}
else {
for(i=0; name[i]; i++)
@@ -311,9 +316,9 @@ putsymb(Sym *s, char *name, int t, vlong v, vlong size, int ver, Sym *typ)
return;
}
if(ver)
- Bprint(&bso, "%c %.8llux %s<%d> %s\n", t, v, s, ver, typ ? typ->name : "");
+ Bprint(&bso, "%c %.8llux %s<%d> %s\n", t, v, s->name, ver, typ ? typ->name : "");
else
- Bprint(&bso, "%c %.8llux %s %s\n", t, v, s, typ ? typ->name : "");
+ Bprint(&bso, "%c %.8llux %s %s\n", t, v, s->name, typ ? typ->name : "");
}
}
diff --git a/src/cmd/nm/Makefile b/src/cmd/nm/Makefile
index 383dbd973..81bc348de 100644
--- a/src/cmd/nm/Makefile
+++ b/src/cmd/nm/Makefile
@@ -12,7 +12,4 @@ TARG=6nm
OFILES=\
nm.$O\
-LIB=\
- ../../../lib/libmach.a\
-
include ../../Make.ccmd
diff --git a/src/cmd/prof/Makefile b/src/cmd/prof/Makefile
index e643f267c..8a1a2f308 100644
--- a/src/cmd/prof/Makefile
+++ b/src/cmd/prof/Makefile
@@ -13,9 +13,6 @@ TARG=6prof
OFILES=\
main.$O\
-LIB=\
- ../../../lib/libmach.a\
-
NOINSTALL=1
include ../../Make.ccmd
diff --git a/src/cmd/prof/gopprof b/src/cmd/prof/gopprof
index 8863fc623..be5f84e9e 100755
--- a/src/cmd/prof/gopprof
+++ b/src/cmd/prof/gopprof
@@ -150,7 +150,8 @@ pprof [options] <profile>
The /<service> can be $HEAP_PAGE, $PROFILE_PAGE, /pprof/pmuprofile,
$GROWTH_PAGE, $CONTENTION_PAGE, /pprof/wall,
or /pprof/filteredprofile.
- For instance: "pprof http://myserver.com:80$HEAP_PAGE".
+ For instance:
+ pprof http://myserver.com:80$HEAP_PAGE
If /<service> is omitted, the service defaults to $PROFILE_PAGE (cpu profiling).
pprof --symbols <program>
Maps addresses to symbol names. In this mode, stdin should be a
@@ -532,7 +533,7 @@ sub Init() {
ConfigureObjTools($main::prog)
}
- # Break the opt_list_prefix into the prefix_list array
+ # Break the opt_lib_prefix into the prefix_list array
@prefix_list = split (',', $main::opt_lib_prefix);
# Remove trailing / from the prefixes, in the list to prevent
@@ -626,7 +627,7 @@ sub Main() {
if ($main::opt_disasm) {
PrintDisassembly($libs, $flat, $cumulative, $main::opt_disasm, $total);
} elsif ($main::opt_list) {
- PrintListing($libs, $flat, $cumulative, $main::opt_list);
+ PrintListing($total, $libs, $flat, $cumulative, $main::opt_list, 0);
} elsif ($main::opt_text) {
# Make sure the output is empty when have nothing to report
# (only matters when --heapcheck is given but we must be
@@ -814,7 +815,7 @@ sub InteractiveCommand {
my $ignore;
($routine, $ignore) = ParseInteractiveArgs($3);
- my $profile = ProcessProfile($orig_profile, $symbols, "", $ignore);
+ my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore);
my $reduced = ReduceProfile($symbols, $profile);
# Get derived profiles
@@ -841,21 +842,22 @@ sub InteractiveCommand {
return 1;
}
- if (m/^\s*list\s*(.+)/) {
+ if (m/^\s*(web)?list\s*(.+)/) {
+ my $html = (defined($1) && ($1 eq "web"));
$main::opt_list = 1;
my $routine;
my $ignore;
- ($routine, $ignore) = ParseInteractiveArgs($1);
+ ($routine, $ignore) = ParseInteractiveArgs($2);
- my $profile = ProcessProfile($orig_profile, $symbols, "", $ignore);
+ my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore);
my $reduced = ReduceProfile($symbols, $profile);
# Get derived profiles
my $flat = FlatProfile($reduced);
my $cumulative = CumulativeProfile($reduced);
- PrintListing($libs, $flat, $cumulative, $routine);
+ PrintListing($total, $libs, $flat, $cumulative, $routine, $html);
return 1;
}
if (m/^\s*disasm\s*(.+)/) {
@@ -866,7 +868,7 @@ sub InteractiveCommand {
($routine, $ignore) = ParseInteractiveArgs($1);
# Process current profile to account for various settings
- my $profile = ProcessProfile($orig_profile, $symbols, "", $ignore);
+ my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore);
my $reduced = ReduceProfile($symbols, $profile);
# Get derived profiles
@@ -890,7 +892,7 @@ sub InteractiveCommand {
($focus, $ignore) = ParseInteractiveArgs($2);
# Process current profile to account for various settings
- my $profile = ProcessProfile($orig_profile, $symbols, $focus, $ignore);
+ my $profile = ProcessProfile($total, $orig_profile, $symbols, $focus, $ignore);
my $reduced = ReduceProfile($symbols, $profile);
# Get derived profiles
@@ -916,6 +918,7 @@ sub InteractiveCommand {
sub ProcessProfile {
+ my $total_count = shift;
my $orig_profile = shift;
my $symbols = shift;
my $focus = shift;
@@ -923,7 +926,6 @@ sub ProcessProfile {
# Process current profile to account for various settings
my $profile = $orig_profile;
- my $total_count = TotalProfile($profile);
printf("Total: %s %s\n", Unparse($total_count), Units());
if ($focus ne '') {
$profile = FocusProfile($symbols, $profile, $focus);
@@ -970,6 +972,11 @@ Commands:
list [routine_regexp] [-ignore1] [-ignore2]
Show source listing of routines whose names match "routine_regexp"
+ weblist [routine_regexp] [-ignore1] [-ignore2]
+ Displays a source listing of routines whose names match "routine_regexp"
+ in a web browser. You can click on source lines to view the
+ corresponding disassembly.
+
top [--cum] [-ignore1] [-ignore2]
top20 [--cum] [-ignore1] [-ignore2]
top37 [--cum] [-ignore1] [-ignore2]
@@ -1144,7 +1151,7 @@ sub PrintText {
$sym);
}
$lines++;
- last if ($line_limit >= 0 && $lines > $line_limit);
+ last if ($line_limit >= 0 && $lines >= $line_limit);
}
}
@@ -1291,11 +1298,32 @@ sub ByName {
# Print source-listing for all all routines that match $main::opt_list
sub PrintListing {
+ my $total = shift;
my $libs = shift;
my $flat = shift;
my $cumulative = shift;
my $list_opts = shift;
-
+ my $html = shift;
+
+ my $output = \*STDOUT;
+ my $fname = "";
+
+
+ if ($html) {
+ # Arrange to write the output to a temporary file
+ $fname = TempName($main::next_tmpfile, "html");
+ $main::next_tmpfile++;
+ if (!open(TEMP, ">$fname")) {
+ print STDERR "$fname: $!\n";
+ return;
+ }
+ $output = \*TEMP;
+ print $output HtmlListingHeader();
+ printf $output ("<div class=\"legend\">%s<br>Total: %s %s</div>\n",
+ $main::prog, Unparse($total), Units());
+ }
+
+ my $listed = 0;
foreach my $lib (@{$libs}) {
my $symbol_table = GetProcedureBoundaries($lib->[0], $list_opts);
my $offset = AddressSub($lib->[1], $lib->[3]);
@@ -1307,15 +1335,98 @@ sub PrintListing {
my $addr = AddressAdd($start_addr, $offset);
for (my $i = 0; $i < $length; $i++) {
if (defined($cumulative->{$addr})) {
- PrintSource($lib->[0], $offset,
- $routine, $flat, $cumulative,
- $start_addr, $end_addr);
+ $listed += PrintSource(
+ $lib->[0], $offset,
+ $routine, $flat, $cumulative,
+ $start_addr, $end_addr,
+ $html,
+ $output);
last;
}
$addr = AddressInc($addr);
}
}
}
+
+ if ($html) {
+ if ($listed > 0) {
+ print $output HtmlListingFooter();
+ close($output);
+ RunWeb($fname);
+ } else {
+ close($output);
+ unlink($fname);
+ }
+ }
+}
+
+sub HtmlListingHeader {
+ return <<'EOF';
+<DOCTYPE html>
+<html>
+<head>
+<title>Pprof listing</title>
+<style type="text/css">
+body {
+ font-family: sans-serif;
+}
+h1 {
+ font-size: 1.5em;
+ margin-bottom: 4px;
+}
+.legend {
+ font-size: 1.25em;
+}
+.line {
+ color: #aaaaaa;
+}
+.livesrc {
+ color: #0000ff;
+ cursor: pointer;
+}
+.livesrc:hover {
+ background-color: #cccccc;
+}
+.asm {
+ color: #888888;
+ display: none;
+}
+</style>
+<script type="text/javascript">
+function pprof_toggle_asm(e) {
+ var target;
+ if (!e) e = window.event;
+ if (e.target) target = e.target;
+ else if (e.srcElement) target = e.srcElement;
+
+ if (target && target.className == "livesrc") {
+ var asm = target.nextSibling;
+ if (asm && asm.className == "asm") {
+ asm.style.display = (asm.style.display == "block" ? "none" : "block");
+ e.preventDefault();
+ return false;
+ }
+ }
+}
+</script>
+</head>
+<body>
+EOF
+}
+
+sub HtmlListingFooter {
+ return <<'EOF';
+</body>
+</html>
+EOF
+}
+
+sub HtmlEscape {
+ my $text = shift;
+ $text =~ s/&/&amp;/g;
+ $text =~ s/</&lt;/g;
+ $text =~ s/>/&gt;/g;
+ return $text;
}
# Returns the indentation of the line, if it has any non-whitespace
@@ -1338,6 +1449,8 @@ sub PrintSource {
my $cumulative = shift;
my $start_addr = shift;
my $end_addr = shift;
+ my $html = shift;
+ my $output = shift;
# Disassemble all instructions (just to get line numbers)
my @instructions = Disassemble($prog, $offset, $start_addr, $end_addr);
@@ -1353,7 +1466,7 @@ sub PrintSource {
}
if (!defined($filename)) {
print STDERR "no filename found in $routine\n";
- return;
+ return 0;
}
# Hack 2: assume that the largest line number from $filename is the
@@ -1386,7 +1499,7 @@ sub PrintSource {
{
if (!open(FILE, "<$filename")) {
print STDERR "$filename: $!\n";
- return;
+ return 0;
}
my $l = 0;
my $first_indentation = -1;
@@ -1414,12 +1527,21 @@ sub PrintSource {
# Assign all samples to the range $firstline,$lastline,
# Hack 4: If an instruction does not occur in the range, its samples
# are moved to the next instruction that occurs in the range.
- my $samples1 = {};
- my $samples2 = {};
- my $running1 = 0; # Unassigned flat counts
- my $running2 = 0; # Unassigned cumulative counts
- my $total1 = 0; # Total flat counts
- my $total2 = 0; # Total cumulative counts
+ my $samples1 = {}; # Map from line number to flat count
+ my $samples2 = {}; # Map from line number to cumulative count
+ my $running1 = 0; # Unassigned flat counts
+ my $running2 = 0; # Unassigned cumulative counts
+ my $total1 = 0; # Total flat counts
+ my $total2 = 0; # Total cumulative counts
+ my %disasm = (); # Map from line number to disassembly
+ my $running_disasm = ""; # Unassigned disassembly
+ my $skip_marker = "---\n";
+ if ($html) {
+ $skip_marker = "";
+ for (my $l = $firstline; $l <= $lastline; $l++) {
+ $disasm{$l} = "";
+ }
+ }
foreach my $e (@instructions) {
# Add up counts for all address that fall inside this instruction
my $c1 = 0;
@@ -1428,6 +1550,15 @@ sub PrintSource {
$c1 += GetEntry($flat, $a);
$c2 += GetEntry($cumulative, $a);
}
+
+ if ($html) {
+ $running_disasm .= sprintf(" %6s %6s \t\t%8s: %s\n",
+ HtmlPrintNumber($c1),
+ HtmlPrintNumber($c2),
+ $e->[0],
+ CleanDisassembly($e->[3]));
+ }
+
$running1 += $c1;
$running2 += $c2;
$total1 += $c1;
@@ -1442,6 +1573,10 @@ sub PrintSource {
AddEntry($samples2, $line, $running2);
$running1 = 0;
$running2 = 0;
+ if ($html) {
+ $disasm{$line} .= $running_disasm;
+ $running_disasm = '';
+ }
}
}
@@ -1449,16 +1584,28 @@ sub PrintSource {
AddEntry($samples1, $lastline, $running1);
AddEntry($samples2, $lastline, $running2);
- printf("ROUTINE ====================== %s in %s\n" .
- "%6s %6s Total %s (flat / cumulative)\n",
- ShortFunctionName($routine),
- $filename,
- Units(),
- Unparse($total1),
- Unparse($total2));
+ if ($html) {
+ printf $output (
+ "<h1>%s</h1>%s\n<pre onClick=\"pprof_toggle_asm()\">\n" .
+ "Total:%6s %6s (flat / cumulative %s)\n",
+ HtmlEscape(ShortFunctionName($routine)),
+ HtmlEscape($filename),
+ Unparse($total1),
+ Unparse($total2),
+ Units());
+ } else {
+ printf $output (
+ "ROUTINE ====================== %s in %s\n" .
+ "%6s %6s Total %s (flat / cumulative)\n",
+ ShortFunctionName($routine),
+ $filename,
+ Unparse($total1),
+ Unparse($total2),
+ Units());
+ }
if (!open(FILE, "<$filename")) {
print STDERR "$filename: $!\n";
- return;
+ return 0;
}
my $l = 0;
while (<FILE>) {
@@ -1468,16 +1615,47 @@ sub PrintSource {
(($l <= $oldlastline + 5) || ($l <= $lastline))) {
chop;
my $text = $_;
- if ($l == $firstline) { printf("---\n"); }
- printf("%6s %6s %4d: %s\n",
- UnparseAlt(GetEntry($samples1, $l)),
- UnparseAlt(GetEntry($samples2, $l)),
- $l,
- $text);
- if ($l == $lastline) { printf("---\n"); }
+ if ($l == $firstline) { print $output $skip_marker; }
+ my $n1 = GetEntry($samples1, $l);
+ my $n2 = GetEntry($samples2, $l);
+ if ($html) {
+ my $dis = $disasm{$l};
+ if (!defined($dis) || $n1 + $n2 == 0) {
+ # No samples/disassembly for this source line
+ printf $output (
+ "<span class=\"line\">%5d</span> " .
+ "<span class=\"deadsrc\">%6s %6s %s</span>\n",
+ $l,
+ HtmlPrintNumber($n1),
+ HtmlPrintNumber($n2),
+ HtmlEscape($text));
+ } else {
+ printf $output (
+ "<span class=\"line\">%5d</span> " .
+ "<span class=\"livesrc\">%6s %6s %s</span>" .
+ "<span class=\"asm\">%s</span>\n",
+ $l,
+ HtmlPrintNumber($n1),
+ HtmlPrintNumber($n2),
+ HtmlEscape($text),
+ HtmlEscape($dis));
+ }
+ } else {
+ printf $output(
+ "%6s %6s %4d: %s\n",
+ UnparseAlt($n1),
+ UnparseAlt($n2),
+ $l,
+ $text);
+ }
+ if ($l == $lastline) { print $output $skip_marker; }
};
}
close(FILE);
+ if ($html) {
+ print $output "</pre>\n";
+ }
+ return 1;
}
# Return the source line for the specified file/linenumber.
@@ -1625,16 +1803,11 @@ sub PrintDisassembledFunction {
$address =~ s/^0x//;
$address =~ s/^0*//;
- # Trim symbols
- my $d = $e->[3];
- while ($d =~ s/\([^()%]*\)(\s*const)?//g) { } # Argument types, not (%rax)
- while ($d =~ s/(\w+)<[^<>]*>/$1/g) { } # Remove template arguments
-
printf("%6s %6s %8s: %6s\n",
UnparseAlt($flat_count[$x]),
UnparseAlt($cum_count[$x]),
$address,
- $d);
+ CleanDisassembly($e->[3]));
}
}
}
@@ -2254,6 +2427,16 @@ sub UnparseAlt {
}
}
+# Alternate pretty-printed form: 0 maps to ""
+sub HtmlPrintNumber {
+ my $num = shift;
+ if ($num == 0) {
+ return "";
+ } else {
+ return Unparse($num);
+ }
+}
+
# Return output units
sub Units {
if ($main::profile_type eq 'heap' || $main::profile_type eq 'growth') {
@@ -2415,6 +2598,8 @@ sub RemoveUninterestingFrames {
'copyin',
'gostring',
'gostringsize',
+ 'growslice1',
+ 'appendslice1',
'hash_init',
'hash_subtable_new',
'hash_conv',
@@ -2422,6 +2607,8 @@ sub RemoveUninterestingFrames {
'hash_insert_internal',
'hash_insert',
'mapassign',
+ 'runtime.mapassign',
+ 'runtime.appendslice',
'runtime.mapassign1',
'makechan',
'makemap',
@@ -2433,11 +2620,13 @@ sub RemoveUninterestingFrames {
'unsafe.New',
'runtime.mallocgc',
'runtime.catstring',
+ 'runtime.growslice',
'runtime.ifaceT2E',
'runtime.ifaceT2I',
'runtime.makechan',
'runtime.makechan_c',
'runtime.makemap',
+ 'runtime.makemap_c',
'runtime.makeslice',
'runtime.mal',
'runtime.slicebytetostring',
@@ -4302,6 +4491,14 @@ sub ShortFunctionName {
return $function;
}
+# Trim overly long symbols found in disassembler output
+sub CleanDisassembly {
+ my $d = shift;
+ while ($d =~ s/\([^()%]*\)(\s*const)?//g) { } # Argument types, not (%rax)
+ while ($d =~ s/(\w+)<[^<>]*>/$1/g) { } # Remove template arguments
+ return $d;
+}
+
##### Miscellaneous #####
# Find the right versions of the above object tools to use. The
diff --git a/src/env.bash b/src/env.bash
index ca3ecebe8..19402f306 100644
--- a/src/env.bash
+++ b/src/env.bash
@@ -39,13 +39,56 @@ if [ ! -d "$GOBIN" -a "$GOBIN" != "$GOROOT/bin" ]; then
fi
export OLDPATH=$PATH
-export PATH="$GOBIN":/bin:/usr/bin:$PATH
+export PATH="$GOBIN":$PATH
MAKE=make
if ! make --version 2>/dev/null | grep 'GNU Make' >/dev/null; then
MAKE=gmake
fi
+PROGS="
+ ar
+ awk
+ bash
+ bison
+ chmod
+ cp
+ cut
+ echo
+ ed
+ egrep
+ gcc
+ grep
+ ls
+ mkdir
+ mv
+ pwd
+ rm
+ sed
+ sort
+ tee
+ touch
+ tr
+ true
+ uname
+ uniq
+"
+
+for i in bison ed awk gcc $MAKE; do
+ if ! which $i >/dev/null 2>&1; then
+ echo "Cannot find '$i' on search path." 1>&2
+ echo "See http://golang.org/doc/install.html#ctools" 1>&2
+ exit 1
+ fi
+done
+
+if bison --version 2>&1 | grep 'bison++' >/dev/null 2>&1; then
+ echo "Your system's 'bison' is bison++."
+ echo "Go needs the original bison instead." 1>&2
+ echo "See http://golang.org/doc/install.html#ctools" 1>&2
+ exit 1
+fi
+
# Tried to use . <($MAKE ...) here, but it cannot set environment
# variables in the version of bash that ships with OS X. Amazing.
eval $($MAKE --no-print-directory -f Make.inc go-env | egrep 'GOARCH|GOOS|GOHOSTARCH|GOHOSTOS|GO_ENV')
diff --git a/src/libmach/8db.c b/src/libmach/8db.c
index 5a195baf8..5b3de69a5 100644
--- a/src/libmach/8db.c
+++ b/src/libmach/8db.c
@@ -1017,14 +1017,56 @@ static Optable optabDB[8+64] =
[0x03] = { 0,0, "FMOVLP F0,%e" },
[0x05] = { 0,0, "FMOVX %e,F0" },
[0x07] = { 0,0, "FMOVXP F0,%e" },
-[0x08] = { 0,0, "FCMOVCC %f,F0" },
-[0x09] = { 0,0, "FCMOVNE %f,F0" },
-[0x0a] = { 0,0, "FCMOVHI %f,F0" },
-[0x0b] = { 0,0, "FCMOVNU %f,F0" },
-[0x0d] = { 0,0, "FUCOMI F0,%f" },
-[0x0e] = { 0,0, "FCOMI F0,%f" },
+[0x08] = { 0,0, "FCMOVCC F0,F0" }, /* Mod R/M = 11xx xxxx*/
+[0x09] = { 0,0, "FCMOVCC F1,F0" },
+[0x0a] = { 0,0, "FCMOVCC F2,F0" },
+[0x0b] = { 0,0, "FCMOVCC F3,F0" },
+[0x0c] = { 0,0, "FCMOVCC F4,F0" },
+[0x0d] = { 0,0, "FCMOVCC F5,F0" },
+[0x0e] = { 0,0, "FCMOVCC F6,F0" },
+[0x0f] = { 0,0, "FCMOVCC F7,F0" },
+[0x10] = { 0,0, "FCMOVNE F0,F0" },
+[0x11] = { 0,0, "FCMOVNE F1,F0" },
+[0x12] = { 0,0, "FCMOVNE F2,F0" },
+[0x13] = { 0,0, "FCMOVNE F3,F0" },
+[0x14] = { 0,0, "FCMOVNE F4,F0" },
+[0x15] = { 0,0, "FCMOVNE F5,F0" },
+[0x16] = { 0,0, "FCMOVNE F6,F0" },
+[0x17] = { 0,0, "FCMOVNE F7,F0" },
+[0x18] = { 0,0, "FCMOVHI F0,F0" },
+[0x19] = { 0,0, "FCMOVHI F1,F0" },
+[0x1a] = { 0,0, "FCMOVHI F2,F0" },
+[0x1b] = { 0,0, "FCMOVHI F3,F0" },
+[0x1c] = { 0,0, "FCMOVHI F4,F0" },
+[0x1d] = { 0,0, "FCMOVHI F5,F0" },
+[0x1e] = { 0,0, "FCMOVHI F6,F0" },
+[0x1f] = { 0,0, "FCMOVHI F7,F0" },
+[0x20] = { 0,0, "FCMOVNU F0,F0" },
+[0x21] = { 0,0, "FCMOVNU F1,F0" },
+[0x22] = { 0,0, "FCMOVNU F2,F0" },
+[0x23] = { 0,0, "FCMOVNU F3,F0" },
+[0x24] = { 0,0, "FCMOVNU F4,F0" },
+[0x25] = { 0,0, "FCMOVNU F5,F0" },
+[0x26] = { 0,0, "FCMOVNU F6,F0" },
+[0x27] = { 0,0, "FCMOVNU F7,F0" },
[0x2a] = { 0,0, "FCLEX" },
[0x2b] = { 0,0, "FINIT" },
+[0x30] = { 0,0, "FUCOMI F0,F0" },
+[0x31] = { 0,0, "FUCOMI F1,F0" },
+[0x32] = { 0,0, "FUCOMI F2,F0" },
+[0x33] = { 0,0, "FUCOMI F3,F0" },
+[0x34] = { 0,0, "FUCOMI F4,F0" },
+[0x35] = { 0,0, "FUCOMI F5,F0" },
+[0x36] = { 0,0, "FUCOMI F6,F0" },
+[0x37] = { 0,0, "FUCOMI F7,F0" },
+[0x38] = { 0,0, "FCOMI F0,F0" },
+[0x39] = { 0,0, "FCOMI F1,F0" },
+[0x3a] = { 0,0, "FCOMI F2,F0" },
+[0x3b] = { 0,0, "FCOMI F3,F0" },
+[0x3c] = { 0,0, "FCOMI F4,F0" },
+[0x3d] = { 0,0, "FCOMI F5,F0" },
+[0x3e] = { 0,0, "FCOMI F6,F0" },
+[0x3f] = { 0,0, "FCOMI F7,F0" },
};
static Optable optabDC[8+8] =
diff --git a/src/libmach/linux.c b/src/libmach/linux.c
index 30b4da240..6ce18957f 100644
--- a/src/libmach/linux.c
+++ b/src/libmach/linux.c
@@ -238,8 +238,7 @@ fixup:
PTRACE_O_TRACEVFORK |
PTRACE_O_TRACECLONE |
PTRACE_O_TRACEEXEC |
- PTRACE_O_TRACEVFORKDONE |
- PTRACE_O_TRACEEXIT;
+ PTRACE_O_TRACEVFORKDONE;
if(ptrace(PTRACE_SETOPTIONS, tid, 0, (void*)flags) < 0) {
fprint(2, "ptrace PTRACE_SETOPTIONS %d: %r\n", tid);
return nil;
@@ -358,6 +357,12 @@ wait1(int nohang)
break;
case PTRACE_EVENT_EXIT:
+ // We won't see this unless we set PTRACE_O_TRACEEXIT.
+ // The debuggers assume that a read or write on a Map
+ // will fail for a thread that has exited. This event
+ // breaks that assumption. It's not a big deal: we
+ // only lose the ability to see the register state at
+ // the time of exit.
if(trace)
fprint(2, "tid %d: exiting %#x\n", tid, status);
t->state = Exiting;
@@ -755,13 +760,19 @@ static int
ptracerw(int type, int xtype, int isr, int pid, uvlong addr, void *v, uint n)
{
int i;
- uintptr u;
+ uintptr u, a;
uchar buf[sizeof(uintptr)];
for(i=0; i<n; i+=sizeof(uintptr)){
+ // Tread carefully here. On recent versions of glibc,
+ // ptrace is a variadic function which means the third
+ // argument will be pushed onto the stack as a uvlong.
+ // This is fine on amd64 but will not work for 386.
+ // We must convert addr to a uintptr.
+ a = addr+i;
if(isr){
errno = 0;
- u = ptrace(type, pid, addr+i, 0);
+ u = ptrace(type, pid, a, 0);
if(errno)
goto ptraceerr;
if(n-i >= sizeof(uintptr))
@@ -775,14 +786,14 @@ ptracerw(int type, int xtype, int isr, int pid, uvlong addr, void *v, uint n)
u = *(uintptr*)((char*)v+i);
else{
errno = 0;
- u = ptrace(xtype, pid, addr+i, 0);
+ u = ptrace(xtype, pid, a, 0);
if(errno)
return -1;
memmove(buf, &u, sizeof u);
memmove(buf, (char*)v+i, n-i);
memmove(&u, buf, sizeof u);
}
- if(ptrace(type, pid, addr+i, u) < 0)
+ if(ptrace(type, pid, a, u) < 0)
goto ptraceerr;
}
}
diff --git a/src/pkg/Makefile b/src/pkg/Makefile
index 2d6b3d014..f18dc1f9b 100644
--- a/src/pkg/Makefile
+++ b/src/pkg/Makefile
@@ -45,6 +45,7 @@ DIRS=\
crypto/ocsp\
crypto/openpgp\
crypto/openpgp/armor\
+ crypto/openpgp/elgamal\
crypto/openpgp/error\
crypto/openpgp/packet\
crypto/openpgp/s2k\
@@ -80,6 +81,7 @@ DIRS=\
exp/eval\
exp/gui\
exp/gui/x11\
+ exp/regexp/syntax\
expvar\
flag\
fmt\
@@ -181,6 +183,36 @@ DIRS+=\
endif
+ifeq ($(GOOS),plan9)
+NOPLAN9BUILD=\
+ crypto/tls\
+ debug/proc\
+ exp/gui/x11\
+ expvar\
+ http\
+ http/cgi\
+ http/fcgi\
+ http/httptest\
+ http/pprof\
+ http/spdy\
+ mail\
+ mime/multipart\
+ net\
+ net/dict\
+ net/textproto\
+ netchan\
+ os/signal\
+ rpc\
+ rpc/jsonrpc\
+ smtp\
+ syslog\
+ websocket\
+ ../cmd/godoc\
+ ../cmd/goinstall\
+
+DIRS:=$(filter-out $(NOPLAN9BUILD),$(DIRS))
+endif
+
NOTEST+=\
crypto\
crypto/openpgp/error\
@@ -206,6 +238,7 @@ NOTEST+=\
../cmd/cgo\
../cmd/ebnflint\
../cmd/godoc\
+ ../cmd/goinstall\
../cmd/gotest\
../cmd/govet\
../cmd/goyacc\
diff --git a/src/pkg/archive/tar/reader.go b/src/pkg/archive/tar/reader.go
index ad06b6dac..45d95c3df 100644
--- a/src/pkg/archive/tar/reader.go
+++ b/src/pkg/archive/tar/reader.go
@@ -16,7 +16,7 @@ import (
)
var (
- HeaderError os.Error = os.ErrorString("invalid tar header")
+ HeaderError = os.NewError("invalid tar header")
)
// A Reader provides sequential access to the contents of a tar archive.
diff --git a/src/pkg/big/int.go b/src/pkg/big/int.go
index 22bdf8d2f..4d47a82d5 100755
--- a/src/pkg/big/int.go
+++ b/src/pkg/big/int.go
@@ -430,7 +430,7 @@ func (z *Int) Scan(s fmt.ScanState, ch int) os.Error {
case 's', 'v':
// let scan determine the base
default:
- return os.ErrorString("Int.Scan: invalid verb")
+ return os.NewError("Int.Scan: invalid verb")
}
_, _, err := z.scan(s, base)
return err
@@ -834,11 +834,11 @@ func (z *Int) GobEncode() ([]byte, os.Error) {
// GobDecode implements the gob.GobDecoder interface.
func (z *Int) GobDecode(buf []byte) os.Error {
if len(buf) == 0 {
- return os.ErrorString("Int.GobDecode: no data")
+ return os.NewError("Int.GobDecode: no data")
}
b := buf[0]
if b>>1 != intGobVersion {
- return os.ErrorString(fmt.Sprintf("Int.GobDecode: encoding version %d not supported", b>>1))
+ return os.NewError(fmt.Sprintf("Int.GobDecode: encoding version %d not supported", b>>1))
}
z.neg = b&1 != 0
z.abs = z.abs.setBytes(buf[1:])
diff --git a/src/pkg/big/nat.go b/src/pkg/big/nat.go
index 734568e06..6755832be 100755
--- a/src/pkg/big/nat.go
+++ b/src/pkg/big/nat.go
@@ -644,7 +644,7 @@ func hexValue(ch int) Word {
func (z nat) scan(r io.RuneScanner, base int) (nat, int, os.Error) {
// reject illegal bases
if base < 0 || base == 1 || MaxBase < base {
- return z, 0, os.ErrorString("illegal number base")
+ return z, 0, os.NewError("illegal number base")
}
// one char look-ahead
@@ -721,7 +721,7 @@ func (z nat) scan(r io.RuneScanner, base int) (nat, int, os.Error) {
return z, 10, nil
case base != 0 || b != 8:
// there was neither a mantissa digit nor the octal prefix 0
- return z, int(b), os.ErrorString("syntax error scanning number")
+ return z, int(b), os.NewError("syntax error scanning number")
}
return z.norm(), int(b), nil
diff --git a/src/pkg/big/rat.go b/src/pkg/big/rat.go
index 1fbf8c459..b61cbb966 100644
--- a/src/pkg/big/rat.go
+++ b/src/pkg/big/rat.go
@@ -227,10 +227,10 @@ func (z *Rat) Scan(s fmt.ScanState, ch int) os.Error {
return err
}
if strings.IndexRune("efgEFGv", ch) < 0 {
- return os.ErrorString("Rat.Scan: invalid verb")
+ return os.NewError("Rat.Scan: invalid verb")
}
if _, ok := z.SetString(string(tok)); !ok {
- return os.ErrorString("Rat.Scan: invalid syntax")
+ return os.NewError("Rat.Scan: invalid syntax")
}
return nil
}
@@ -368,7 +368,7 @@ func (z *Rat) GobEncode() ([]byte, os.Error) {
n := i - j
if int(uint32(n)) != n {
// this should never happen
- return nil, os.ErrorString("Rat.GobEncode: numerator too large")
+ return nil, os.NewError("Rat.GobEncode: numerator too large")
}
binary.BigEndian.PutUint32(buf[j-4:j], uint32(n))
j -= 1 + 4
@@ -384,11 +384,11 @@ func (z *Rat) GobEncode() ([]byte, os.Error) {
// GobDecode implements the gob.GobDecoder interface.
func (z *Rat) GobDecode(buf []byte) os.Error {
if len(buf) == 0 {
- return os.ErrorString("Rat.GobDecode: no data")
+ return os.NewError("Rat.GobDecode: no data")
}
b := buf[0]
if b>>1 != ratGobVersion {
- return os.ErrorString(fmt.Sprintf("Rat.GobDecode: encoding version %d not supported", b>>1))
+ return os.NewError(fmt.Sprintf("Rat.GobDecode: encoding version %d not supported", b>>1))
}
const j = 1 + 4
i := j + binary.BigEndian.Uint32(buf[j-4:j])
diff --git a/src/pkg/bufio/bufio.go b/src/pkg/bufio/bufio.go
index eaae8bb42..497e770fb 100644
--- a/src/pkg/bufio/bufio.go
+++ b/src/pkg/bufio/bufio.go
@@ -22,9 +22,11 @@ const (
// Errors introduced by this package.
type Error struct {
- os.ErrorString
+ ErrorString string
}
+func (err *Error) String() string { return err.ErrorString }
+
var (
ErrInvalidUnreadByte os.Error = &Error{"bufio: invalid use of UnreadByte"}
ErrInvalidUnreadRune os.Error = &Error{"bufio: invalid use of UnreadRune"}
diff --git a/src/pkg/bytes/buffer.go b/src/pkg/bytes/buffer.go
index 1acd4e05c..5de86105d 100644
--- a/src/pkg/bytes/buffer.go
+++ b/src/pkg/bytes/buffer.go
@@ -280,7 +280,7 @@ func (b *Buffer) ReadRune() (r int, size int, err os.Error) {
// from any read operation.)
func (b *Buffer) UnreadRune() os.Error {
if b.lastRead != opReadRune {
- return os.ErrorString("bytes.Buffer: UnreadRune: previous operation was not ReadRune")
+ return os.NewError("bytes.Buffer: UnreadRune: previous operation was not ReadRune")
}
b.lastRead = opInvalid
if b.off > 0 {
@@ -295,7 +295,7 @@ func (b *Buffer) UnreadRune() os.Error {
// returns an error.
func (b *Buffer) UnreadByte() os.Error {
if b.lastRead != opReadRune && b.lastRead != opRead {
- return os.ErrorString("bytes.Buffer: UnreadByte: previous operation was not a read")
+ return os.NewError("bytes.Buffer: UnreadByte: previous operation was not a read")
}
b.lastRead = opInvalid
if b.off > 0 {
diff --git a/src/pkg/compress/gzip/gunzip.go b/src/pkg/compress/gzip/gunzip.go
index b0ddc81d2..6ac9293d7 100644
--- a/src/pkg/compress/gzip/gunzip.go
+++ b/src/pkg/compress/gzip/gunzip.go
@@ -36,8 +36,8 @@ func makeReader(r io.Reader) flate.Reader {
return bufio.NewReader(r)
}
-var HeaderError os.Error = os.ErrorString("invalid gzip header")
-var ChecksumError os.Error = os.ErrorString("gzip checksum error")
+var HeaderError = os.NewError("invalid gzip header")
+var ChecksumError = os.NewError("gzip checksum error")
// The gzip file stores a header giving metadata about the compressed file.
// That header is exposed as the fields of the Compressor and Decompressor structs.
diff --git a/src/pkg/compress/zlib/reader.go b/src/pkg/compress/zlib/reader.go
index 8a3ef1580..78dabdf4d 100644
--- a/src/pkg/compress/zlib/reader.go
+++ b/src/pkg/compress/zlib/reader.go
@@ -34,9 +34,9 @@ import (
const zlibDeflate = 8
-var ChecksumError os.Error = os.ErrorString("zlib checksum error")
-var HeaderError os.Error = os.ErrorString("invalid zlib header")
-var DictionaryError os.Error = os.ErrorString("invalid zlib dictionary")
+var ChecksumError = os.NewError("zlib checksum error")
+var HeaderError = os.NewError("invalid zlib header")
+var DictionaryError = os.NewError("invalid zlib dictionary")
type reader struct {
r flate.Reader
diff --git a/src/pkg/crypto/cast5/cast5.go b/src/pkg/crypto/cast5/cast5.go
index cb62e3132..e9d4a24e2 100644
--- a/src/pkg/crypto/cast5/cast5.go
+++ b/src/pkg/crypto/cast5/cast5.go
@@ -20,7 +20,7 @@ type Cipher struct {
func NewCipher(key []byte) (c *Cipher, err os.Error) {
if len(key) != KeySize {
- return nil, os.ErrorString("CAST5: keys must be 16 bytes")
+ return nil, os.NewError("CAST5: keys must be 16 bytes")
}
c = new(Cipher)
diff --git a/src/pkg/crypto/dsa/dsa.go b/src/pkg/crypto/dsa/dsa.go
index f0af8bb42..a5f96fe94 100644
--- a/src/pkg/crypto/dsa/dsa.go
+++ b/src/pkg/crypto/dsa/dsa.go
@@ -79,7 +79,7 @@ func GenerateParameters(params *Parameters, rand io.Reader, sizes ParameterSizes
L = 3072
N = 256
default:
- return os.ErrorString("crypto/dsa: invalid ParameterSizes")
+ return os.NewError("crypto/dsa: invalid ParameterSizes")
}
qBytes := make([]byte, N/8)
@@ -158,7 +158,7 @@ GeneratePrimes:
// PrivateKey must already be valid (see GenerateParameters).
func GenerateKey(priv *PrivateKey, rand io.Reader) os.Error {
if priv.P == nil || priv.Q == nil || priv.G == nil {
- return os.ErrorString("crypto/dsa: parameters not set up before generating key")
+ return os.NewError("crypto/dsa: parameters not set up before generating key")
}
x := new(big.Int)
diff --git a/src/pkg/crypto/openpgp/elgamal/Makefile b/src/pkg/crypto/openpgp/elgamal/Makefile
new file mode 100644
index 000000000..f730255f8
--- /dev/null
+++ b/src/pkg/crypto/openpgp/elgamal/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../../Make.inc
+
+TARG=crypto/openpgp/elgamal
+GOFILES=\
+ elgamal.go\
+
+include ../../../../Make.pkg
diff --git a/src/pkg/crypto/openpgp/elgamal/elgamal.go b/src/pkg/crypto/openpgp/elgamal/elgamal.go
new file mode 100644
index 000000000..99a6e3e1f
--- /dev/null
+++ b/src/pkg/crypto/openpgp/elgamal/elgamal.go
@@ -0,0 +1,122 @@
+// 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 elgamal implements ElGamal encryption, suitable for OpenPGP,
+// as specified in "A Public-Key Cryptosystem and a Signature Scheme Based on
+// Discrete Logarithms," IEEE Transactions on Information Theory, v. IT-31,
+// n. 4, 1985, pp. 469-472.
+//
+// This form of ElGamal embeds PKCS#1 v1.5 padding, which may make it
+// unsuitable for other protocols. RSA should be used in preference in any
+// case.
+package elgamal
+
+import (
+ "big"
+ "crypto/rand"
+ "crypto/subtle"
+ "io"
+ "os"
+)
+
+// PublicKey represents an ElGamal public key.
+type PublicKey struct {
+ G, P, Y *big.Int
+}
+
+// PrivateKey represents an ElGamal private key.
+type PrivateKey struct {
+ PublicKey
+ X *big.Int
+}
+
+// Encrypt encrypts the given message to the given public key. The result is a
+// pair of integers. Errors can result from reading random, or because msg is
+// too large to be encrypted to the public key.
+func Encrypt(random io.Reader, pub *PublicKey, msg []byte) (c1, c2 *big.Int, err os.Error) {
+ pLen := (pub.P.BitLen() + 7) / 8
+ if len(msg) > pLen-11 {
+ err = os.NewError("elgamal: message too long")
+ return
+ }
+
+ // EM = 0x02 || PS || 0x00 || M
+ em := make([]byte, pLen-1)
+ em[0] = 2
+ ps, mm := em[1:len(em)-len(msg)-1], em[len(em)-len(msg):]
+ err = nonZeroRandomBytes(ps, random)
+ if err != nil {
+ return
+ }
+ em[len(em)-len(msg)-1] = 0
+ copy(mm, msg)
+
+ m := new(big.Int).SetBytes(em)
+
+ k, err := rand.Int(random, pub.P)
+ if err != nil {
+ return
+ }
+
+ c1 = new(big.Int).Exp(pub.G, k, pub.P)
+ s := new(big.Int).Exp(pub.Y, k, pub.P)
+ c2 = s.Mul(s, m)
+ c2.Mod(c2, pub.P)
+
+ return
+}
+
+// Decrypt takes two integers, resulting from an ElGamal encryption, and
+// returns the plaintext of the message. An error can result only if the
+// ciphertext is invalid. Users should keep in mind that this is a padding
+// oracle and thus, if exposed to an adaptive chosen ciphertext attack, can
+// be used to break the cryptosystem. See ``Chosen Ciphertext Attacks
+// Against Protocols Based on the RSA Encryption Standard PKCS #1'', Daniel
+// Bleichenbacher, Advances in Cryptology (Crypto '98),
+func Decrypt(priv *PrivateKey, c1, c2 *big.Int) (msg []byte, err os.Error) {
+ s := new(big.Int).Exp(c1, priv.X, priv.P)
+ s.ModInverse(s, priv.P)
+ s.Mul(s, c2)
+ s.Mod(s, priv.P)
+ em := s.Bytes()
+
+ firstByteIsTwo := subtle.ConstantTimeByteEq(em[0], 2)
+
+ // The remainder of the plaintext must be a string of non-zero random
+ // octets, followed by a 0, followed by the message.
+ // lookingForIndex: 1 iff we are still looking for the zero.
+ // index: the offset of the first zero byte.
+ var lookingForIndex, index int
+ lookingForIndex = 1
+
+ for i := 1; i < len(em); i++ {
+ equals0 := subtle.ConstantTimeByteEq(em[i], 0)
+ index = subtle.ConstantTimeSelect(lookingForIndex&equals0, i, index)
+ lookingForIndex = subtle.ConstantTimeSelect(equals0, 0, lookingForIndex)
+ }
+
+ if firstByteIsTwo != 1 || lookingForIndex != 0 || index < 9 {
+ return nil, os.NewError("elgamal: decryption error")
+ }
+ return em[index+1:], nil
+}
+
+// nonZeroRandomBytes fills the given slice with non-zero random octets.
+func nonZeroRandomBytes(s []byte, rand io.Reader) (err os.Error) {
+ _, err = io.ReadFull(rand, s)
+ if err != nil {
+ return
+ }
+
+ for i := 0; i < len(s); i++ {
+ for s[i] == 0 {
+ _, err = io.ReadFull(rand, s[i:i+1])
+ if err != nil {
+ return
+ }
+ }
+ }
+
+ return
+}
diff --git a/src/pkg/crypto/openpgp/elgamal/elgamal_test.go b/src/pkg/crypto/openpgp/elgamal/elgamal_test.go
new file mode 100644
index 000000000..101121aa6
--- /dev/null
+++ b/src/pkg/crypto/openpgp/elgamal/elgamal_test.go
@@ -0,0 +1,49 @@
+// 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 elgamal
+
+import (
+ "big"
+ "bytes"
+ "crypto/rand"
+ "testing"
+)
+
+// This is the 1024-bit MODP group from RFC 5114, section 2.1:
+const primeHex = "B10B8F96A080E01DDE92DE5EAE5D54EC52C99FBCFB06A3C69A6A9DCA52D23B616073E28675A23D189838EF1E2EE652C013ECB4AEA906112324975C3CD49B83BFACCBDD7D90C4BD7098488E9C219A73724EFFD6FAE5644738FAA31A4FF55BCCC0A151AF5F0DC8B4BD45BF37DF365C1A65E68CFDA76D4DA708DF1FB2BC2E4A4371"
+
+const generatorHex = "A4D1CBD5C3FD34126765A442EFB99905F8104DD258AC507FD6406CFF14266D31266FEA1E5C41564B777E690F5504F213160217B4B01B886A5E91547F9E2749F4D7FBD7D3B9A92EE1909D0D2263F80A76A6A24C087A091F531DBF0A0169B6A28AD662A4D18E73AFA32D779D5918D08BC8858F4DCEF97C2A24855E6EEB22B3B2E5"
+
+func fromHex(hex string) *big.Int {
+ n, ok := new(big.Int).SetString(hex, 16)
+ if !ok {
+ panic("failed to parse hex number")
+ }
+ return n
+}
+
+func TestEncryptDecrypt(t *testing.T) {
+ priv := &PrivateKey{
+ PublicKey: PublicKey{
+ G: fromHex(generatorHex),
+ P: fromHex(primeHex),
+ },
+ X: fromHex("42"),
+ }
+ priv.Y = new(big.Int).Exp(priv.G, priv.X, priv.P)
+
+ message := []byte("hello world")
+ c1, c2, err := Encrypt(rand.Reader, &priv.PublicKey, message)
+ if err != nil {
+ t.Errorf("error encrypting: %s", err)
+ }
+ message2, err := Decrypt(priv, c1, c2)
+ if err != nil {
+ t.Errorf("error decrypting: %s", err)
+ }
+ if !bytes.Equal(message2, message) {
+ t.Errorf("decryption failed, got: %x, want: %x", message2, message)
+ }
+}
diff --git a/src/pkg/crypto/openpgp/keys.go b/src/pkg/crypto/openpgp/keys.go
index 2acb7e612..d12d07d7e 100644
--- a/src/pkg/crypto/openpgp/keys.go
+++ b/src/pkg/crypto/openpgp/keys.go
@@ -64,6 +64,78 @@ type KeyRing interface {
DecryptionKeys() []Key
}
+// primaryIdentity returns the Identity marked as primary or the first identity
+// if none are so marked.
+func (e *Entity) primaryIdentity() *Identity {
+ var firstIdentity *Identity
+ for _, ident := range e.Identities {
+ if firstIdentity == nil {
+ firstIdentity = ident
+ }
+ if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId {
+ return ident
+ }
+ }
+ return firstIdentity
+}
+
+// encryptionKey returns the best candidate Key for encrypting a message to the
+// given Entity.
+func (e *Entity) encryptionKey() Key {
+ candidateSubkey := -1
+
+ for i, subkey := range e.Subkeys {
+ if subkey.Sig.FlagsValid && subkey.Sig.FlagEncryptCommunications && subkey.PublicKey.PubKeyAlgo.CanEncrypt() {
+ candidateSubkey = i
+ break
+ }
+ }
+
+ i := e.primaryIdentity()
+
+ if e.PrimaryKey.PubKeyAlgo.CanEncrypt() {
+ // If we don't have any candidate subkeys for encryption and
+ // the primary key doesn't have any usage metadata then we
+ // assume that the primary key is ok. Or, if the primary key is
+ // marked as ok to encrypt to, then we can obviously use it.
+ if candidateSubkey == -1 && !i.SelfSignature.FlagsValid || i.SelfSignature.FlagEncryptCommunications && i.SelfSignature.FlagsValid {
+ return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature}
+ }
+ }
+
+ if candidateSubkey != -1 {
+ subkey := e.Subkeys[candidateSubkey]
+ return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig}
+ }
+
+ // This Entity appears to be signing only.
+ return Key{}
+}
+
+// signingKey return the best candidate Key for signing a message with this
+// Entity.
+func (e *Entity) signingKey() Key {
+ candidateSubkey := -1
+
+ for i, subkey := range e.Subkeys {
+ if subkey.Sig.FlagsValid && subkey.Sig.FlagSign && subkey.PublicKey.PubKeyAlgo.CanSign() {
+ candidateSubkey = i
+ break
+ }
+ }
+
+ i := e.primaryIdentity()
+
+ // If we have no candidate subkey then we assume that it's ok to sign
+ // with the primary key.
+ if candidateSubkey == -1 || i.SelfSignature.FlagsValid && i.SelfSignature.FlagSign {
+ return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature}
+ }
+
+ subkey := e.Subkeys[candidateSubkey]
+ return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig}
+}
+
// An EntityList contains one or more Entities.
type EntityList []*Entity
@@ -199,6 +271,10 @@ func readEntity(packets *packet.Reader) (*Entity, os.Error) {
}
}
+ if !e.PrimaryKey.PubKeyAlgo.CanSign() {
+ return nil, error.StructuralError("primary key cannot be used for signatures")
+ }
+
var current *Identity
EachPacket:
for {
@@ -229,7 +305,7 @@ EachPacket:
return nil, error.StructuralError("user ID packet not followed by self-signature")
}
- if sig.SigType == packet.SigTypePositiveCert && sig.IssuerKeyId != nil && *sig.IssuerKeyId == e.PrimaryKey.KeyId {
+ if (sig.SigType == packet.SigTypePositiveCert || sig.SigType == packet.SigTypeGenericCert) && sig.IssuerKeyId != nil && *sig.IssuerKeyId == e.PrimaryKey.KeyId {
if err = e.PrimaryKey.VerifyUserIdSignature(pkt.Id, sig); err != nil {
return nil, error.StructuralError("user ID self-signature invalid: " + err.String())
}
diff --git a/src/pkg/crypto/openpgp/packet/encrypted_key.go b/src/pkg/crypto/openpgp/packet/encrypted_key.go
index b11a9b830..b4730cbc9 100644
--- a/src/pkg/crypto/openpgp/packet/encrypted_key.go
+++ b/src/pkg/crypto/openpgp/packet/encrypted_key.go
@@ -5,6 +5,8 @@
package packet
import (
+ "big"
+ "crypto/openpgp/elgamal"
"crypto/openpgp/error"
"crypto/rand"
"crypto/rsa"
@@ -14,14 +16,17 @@ import (
"strconv"
)
+const encryptedKeyVersion = 3
+
// EncryptedKey represents a public-key encrypted session key. See RFC 4880,
// section 5.1.
type EncryptedKey struct {
KeyId uint64
Algo PublicKeyAlgorithm
- Encrypted []byte
CipherFunc CipherFunction // only valid after a successful Decrypt
Key []byte // only valid after a successful Decrypt
+
+ encryptedMPI1, encryptedMPI2 []byte
}
func (e *EncryptedKey) parse(r io.Reader) (err os.Error) {
@@ -30,37 +35,134 @@ func (e *EncryptedKey) parse(r io.Reader) (err os.Error) {
if err != nil {
return
}
- if buf[0] != 3 {
+ if buf[0] != encryptedKeyVersion {
return error.UnsupportedError("unknown EncryptedKey version " + strconv.Itoa(int(buf[0])))
}
e.KeyId = binary.BigEndian.Uint64(buf[1:9])
e.Algo = PublicKeyAlgorithm(buf[9])
- if e.Algo == PubKeyAlgoRSA || e.Algo == PubKeyAlgoRSAEncryptOnly {
- e.Encrypted, _, err = readMPI(r)
+ switch e.Algo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
+ e.encryptedMPI1, _, err = readMPI(r)
+ case PubKeyAlgoElGamal:
+ e.encryptedMPI1, _, err = readMPI(r)
+ if err != nil {
+ return
+ }
+ e.encryptedMPI2, _, err = readMPI(r)
}
_, err = consumeAll(r)
return
}
-// DecryptRSA decrypts an RSA encrypted session key with the given private key.
-func (e *EncryptedKey) DecryptRSA(priv *rsa.PrivateKey) (err os.Error) {
- if e.Algo != PubKeyAlgoRSA && e.Algo != PubKeyAlgoRSAEncryptOnly {
- return error.InvalidArgumentError("EncryptedKey not RSA encrypted")
+func checksumKeyMaterial(key []byte) uint16 {
+ var checksum uint16
+ for _, v := range key {
+ checksum += uint16(v)
}
- b, err := rsa.DecryptPKCS1v15(rand.Reader, priv, e.Encrypted)
+ return checksum
+}
+
+// Decrypt decrypts an encrypted session key with the given private key. The
+// private key must have been decrypted first.
+func (e *EncryptedKey) Decrypt(priv *PrivateKey) os.Error {
+ var err os.Error
+ var b []byte
+
+ // TODO(agl): use session key decryption routines here to avoid
+ // padding oracle attacks.
+ switch priv.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
+ b, err = rsa.DecryptPKCS1v15(rand.Reader, priv.PrivateKey.(*rsa.PrivateKey), e.encryptedMPI1)
+ case PubKeyAlgoElGamal:
+ c1 := new(big.Int).SetBytes(e.encryptedMPI1)
+ c2 := new(big.Int).SetBytes(e.encryptedMPI2)
+ b, err = elgamal.Decrypt(priv.PrivateKey.(*elgamal.PrivateKey), c1, c2)
+ default:
+ err = error.InvalidArgumentError("cannot decrypted encrypted session key with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo)))
+ }
+
if err != nil {
- return
+ return err
}
+
e.CipherFunc = CipherFunction(b[0])
e.Key = b[1 : len(b)-2]
expectedChecksum := uint16(b[len(b)-2])<<8 | uint16(b[len(b)-1])
- var checksum uint16
- for _, v := range e.Key {
- checksum += uint16(v)
- }
+ checksum := checksumKeyMaterial(e.Key)
if checksum != expectedChecksum {
return error.StructuralError("EncryptedKey checksum incorrect")
}
- return
+ return nil
+}
+
+// SerializeEncryptedKey serializes an encrypted key packet to w that contains
+// key, encrypted to pub.
+func SerializeEncryptedKey(w io.Writer, rand io.Reader, pub *PublicKey, cipherFunc CipherFunction, key []byte) os.Error {
+ var buf [10]byte
+ buf[0] = encryptedKeyVersion
+ binary.BigEndian.PutUint64(buf[1:9], pub.KeyId)
+ buf[9] = byte(pub.PubKeyAlgo)
+
+ keyBlock := make([]byte, 1 /* cipher type */ +len(key)+2 /* checksum */ )
+ keyBlock[0] = byte(cipherFunc)
+ copy(keyBlock[1:], key)
+ checksum := checksumKeyMaterial(key)
+ keyBlock[1+len(key)] = byte(checksum >> 8)
+ keyBlock[1+len(key)+1] = byte(checksum)
+
+ switch pub.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
+ return serializeEncryptedKeyRSA(w, rand, buf, pub.PublicKey.(*rsa.PublicKey), keyBlock)
+ case PubKeyAlgoElGamal:
+ return serializeEncryptedKeyElGamal(w, rand, buf, pub.PublicKey.(*elgamal.PublicKey), keyBlock)
+ case PubKeyAlgoDSA, PubKeyAlgoRSASignOnly:
+ return error.InvalidArgumentError("cannot encrypt to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
+ }
+
+ return error.UnsupportedError("encrypting a key to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
+}
+
+func serializeEncryptedKeyRSA(w io.Writer, rand io.Reader, header [10]byte, pub *rsa.PublicKey, keyBlock []byte) os.Error {
+ cipherText, err := rsa.EncryptPKCS1v15(rand, pub, keyBlock)
+ if err != nil {
+ return error.InvalidArgumentError("RSA encryption failed: " + err.String())
+ }
+
+ packetLen := 10 /* header length */ + 2 /* mpi size */ + len(cipherText)
+
+ err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
+ if err != nil {
+ return err
+ }
+ _, err = w.Write(header[:])
+ if err != nil {
+ return err
+ }
+ return writeMPI(w, 8*uint16(len(cipherText)), cipherText)
+}
+
+func serializeEncryptedKeyElGamal(w io.Writer, rand io.Reader, header [10]byte, pub *elgamal.PublicKey, keyBlock []byte) os.Error {
+ c1, c2, err := elgamal.Encrypt(rand, pub, keyBlock)
+ if err != nil {
+ return error.InvalidArgumentError("ElGamal encryption failed: " + err.String())
+ }
+
+ packetLen := 10 /* header length */
+ packetLen += 2 /* mpi size */ + (c1.BitLen()+7)/8
+ packetLen += 2 /* mpi size */ + (c2.BitLen()+7)/8
+
+ err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
+ if err != nil {
+ return err
+ }
+ _, err = w.Write(header[:])
+ if err != nil {
+ return err
+ }
+ err = writeBig(w, c1)
+ if err != nil {
+ return err
+ }
+ return writeBig(w, c2)
}
diff --git a/src/pkg/crypto/openpgp/packet/encrypted_key_test.go b/src/pkg/crypto/openpgp/packet/encrypted_key_test.go
index 755ae7a30..b0a14904a 100644
--- a/src/pkg/crypto/openpgp/packet/encrypted_key_test.go
+++ b/src/pkg/crypto/openpgp/packet/encrypted_key_test.go
@@ -6,6 +6,8 @@ package packet
import (
"big"
+ "bytes"
+ "crypto/rand"
"crypto/rsa"
"fmt"
"testing"
@@ -19,7 +21,28 @@ func bigFromBase10(s string) *big.Int {
return b
}
-func TestEncryptedKey(t *testing.T) {
+
+var encryptedKeyPub = rsa.PublicKey{
+ E: 65537,
+ N: bigFromBase10("115804063926007623305902631768113868327816898845124614648849934718568541074358183759250136204762053879858102352159854352727097033322663029387610959884180306668628526686121021235757016368038585212410610742029286439607686208110250133174279811431933746643015923132833417396844716207301518956640020862630546868823"),
+}
+
+var encryptedKeyRSAPriv = &rsa.PrivateKey{
+ PublicKey: encryptedKeyPub,
+ D: bigFromBase10("32355588668219869544751561565313228297765464314098552250409557267371233892496951383426602439009993875125222579159850054973310859166139474359774543943714622292329487391199285040721944491839695981199720170366763547754915493640685849961780092241140181198779299712578774460837139360803883139311171713302987058393"),
+}
+
+var encryptedKeyPriv = &PrivateKey{
+ PublicKey: PublicKey{
+ PubKeyAlgo: PubKeyAlgoRSA,
+ },
+ PrivateKey: encryptedKeyRSAPriv,
+}
+
+func TestDecryptingEncryptedKey(t *testing.T) {
+ const encryptedKeyHex = "c18c032a67d68660df41c70104005789d0de26b6a50c985a02a13131ca829c413a35d0e6fa8d6842599252162808ac7439c72151c8c6183e76923fe3299301414d0c25a2f06a2257db3839e7df0ec964773f6e4c4ac7ff3b48c444237166dd46ba8ff443a5410dc670cb486672fdbe7c9dfafb75b4fea83af3a204fe2a7dfa86bd20122b4f3d2646cbeecb8f7be8"
+ const expectedKeyHex = "d930363f7e0308c333b9618617ea728963d8df993665ae7be1092d4926fd864b"
+
p, err := Read(readerFromHex(encryptedKeyHex))
if err != nil {
t.Errorf("error from Read: %s", err)
@@ -36,23 +59,63 @@ func TestEncryptedKey(t *testing.T) {
return
}
- pub := rsa.PublicKey{
- E: 65537,
- N: bigFromBase10("115804063926007623305902631768113868327816898845124614648849934718568541074358183759250136204762053879858102352159854352727097033322663029387610959884180306668628526686121021235757016368038585212410610742029286439607686208110250133174279811431933746643015923132833417396844716207301518956640020862630546868823"),
+ err = ek.Decrypt(encryptedKeyPriv)
+ if err != nil {
+ t.Errorf("error from Decrypt: %s", err)
+ return
}
- priv := &rsa.PrivateKey{
- PublicKey: pub,
- D: bigFromBase10("32355588668219869544751561565313228297765464314098552250409557267371233892496951383426602439009993875125222579159850054973310859166139474359774543943714622292329487391199285040721944491839695981199720170366763547754915493640685849961780092241140181198779299712578774460837139360803883139311171713302987058393"),
+ if ek.CipherFunc != CipherAES256 {
+ t.Errorf("unexpected EncryptedKey contents: %#v", ek)
+ return
+ }
+
+ keyHex := fmt.Sprintf("%x", ek.Key)
+ if keyHex != expectedKeyHex {
+ t.Errorf("bad key, got %s want %x", keyHex, expectedKeyHex)
}
+}
- err = ek.DecryptRSA(priv)
+func TestEncryptingEncryptedKey(t *testing.T) {
+ key := []byte{1, 2, 3, 4}
+ const expectedKeyHex = "01020304"
+ const keyId = 42
+
+ pub := &PublicKey{
+ PublicKey: &encryptedKeyPub,
+ KeyId: keyId,
+ PubKeyAlgo: PubKeyAlgoRSAEncryptOnly,
+ }
+
+ buf := new(bytes.Buffer)
+ err := SerializeEncryptedKey(buf, rand.Reader, pub, CipherAES128, key)
+ if err != nil {
+ t.Errorf("error writing encrypted key packet: %s", err)
+ }
+
+ p, err := Read(buf)
+ if err != nil {
+ t.Errorf("error from Read: %s", err)
+ return
+ }
+ ek, ok := p.(*EncryptedKey)
+ if !ok {
+ t.Errorf("didn't parse an EncryptedKey, got %#v", p)
+ return
+ }
+
+ if ek.KeyId != keyId || ek.Algo != PubKeyAlgoRSAEncryptOnly {
+ t.Errorf("unexpected EncryptedKey contents: %#v", ek)
+ return
+ }
+
+ err = ek.Decrypt(encryptedKeyPriv)
if err != nil {
- t.Errorf("error from DecryptRSA: %s", err)
+ t.Errorf("error from Decrypt: %s", err)
return
}
- if ek.CipherFunc != CipherAES256 {
+ if ek.CipherFunc != CipherAES128 {
t.Errorf("unexpected EncryptedKey contents: %#v", ek)
return
}
@@ -62,6 +125,3 @@ func TestEncryptedKey(t *testing.T) {
t.Errorf("bad key, got %s want %x", keyHex, expectedKeyHex)
}
}
-
-const encryptedKeyHex = "c18c032a67d68660df41c70104005789d0de26b6a50c985a02a13131ca829c413a35d0e6fa8d6842599252162808ac7439c72151c8c6183e76923fe3299301414d0c25a2f06a2257db3839e7df0ec964773f6e4c4ac7ff3b48c444237166dd46ba8ff443a5410dc670cb486672fdbe7c9dfafb75b4fea83af3a204fe2a7dfa86bd20122b4f3d2646cbeecb8f7be8"
-const expectedKeyHex = "d930363f7e0308c333b9618617ea728963d8df993665ae7be1092d4926fd864b"
diff --git a/src/pkg/crypto/openpgp/packet/one_pass_signature.go b/src/pkg/crypto/openpgp/packet/one_pass_signature.go
index acbf58bbe..ca826e4f4 100644
--- a/src/pkg/crypto/openpgp/packet/one_pass_signature.go
+++ b/src/pkg/crypto/openpgp/packet/one_pass_signature.go
@@ -24,6 +24,8 @@ type OnePassSignature struct {
IsLast bool
}
+const onePassSignatureVersion = 3
+
func (ops *OnePassSignature) parse(r io.Reader) (err os.Error) {
var buf [13]byte
@@ -31,7 +33,7 @@ func (ops *OnePassSignature) parse(r io.Reader) (err os.Error) {
if err != nil {
return
}
- if buf[0] != 3 {
+ if buf[0] != onePassSignatureVersion {
err = error.UnsupportedError("one-pass-signature packet version " + strconv.Itoa(int(buf[0])))
}
@@ -47,3 +49,26 @@ func (ops *OnePassSignature) parse(r io.Reader) (err os.Error) {
ops.IsLast = buf[12] != 0
return
}
+
+// Serialize marshals the given OnePassSignature to w.
+func (ops *OnePassSignature) Serialize(w io.Writer) os.Error {
+ var buf [13]byte
+ buf[0] = onePassSignatureVersion
+ buf[1] = uint8(ops.SigType)
+ var ok bool
+ buf[2], ok = s2k.HashToHashId(ops.Hash)
+ if !ok {
+ return error.UnsupportedError("hash type: " + strconv.Itoa(int(ops.Hash)))
+ }
+ buf[3] = uint8(ops.PubKeyAlgo)
+ binary.BigEndian.PutUint64(buf[4:12], ops.KeyId)
+ if ops.IsLast {
+ buf[12] = 1
+ }
+
+ if err := serializeHeader(w, packetTypeOnePassSignature, len(buf)); err != nil {
+ return err
+ }
+ _, err := w.Write(buf[:])
+ return err
+}
diff --git a/src/pkg/crypto/openpgp/packet/packet.go b/src/pkg/crypto/openpgp/packet/packet.go
index 640a5b76f..1d7297e38 100644
--- a/src/pkg/crypto/openpgp/packet/packet.go
+++ b/src/pkg/crypto/openpgp/packet/packet.go
@@ -372,10 +372,30 @@ const (
PubKeyAlgoRSA PublicKeyAlgorithm = 1
PubKeyAlgoRSAEncryptOnly PublicKeyAlgorithm = 2
PubKeyAlgoRSASignOnly PublicKeyAlgorithm = 3
- PubKeyAlgoElgamal PublicKeyAlgorithm = 16
+ PubKeyAlgoElGamal PublicKeyAlgorithm = 16
PubKeyAlgoDSA PublicKeyAlgorithm = 17
)
+// CanEncrypt returns true if it's possible to encrypt a message to a public
+// key of the given type.
+func (pka PublicKeyAlgorithm) CanEncrypt() bool {
+ switch pka {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoElGamal:
+ return true
+ }
+ return false
+}
+
+// CanSign returns true if it's possible for a public key of the given type to
+// sign a message.
+func (pka PublicKeyAlgorithm) CanSign() bool {
+ switch pka {
+ case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA:
+ return true
+ }
+ return false
+}
+
// CipherFunction represents the different block ciphers specified for OpenPGP. See
// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-13
type CipherFunction uint8
@@ -387,8 +407,8 @@ const (
CipherAES256 CipherFunction = 9
)
-// keySize returns the key size, in bytes, of cipher.
-func (cipher CipherFunction) keySize() int {
+// KeySize returns the key size, in bytes, of cipher.
+func (cipher CipherFunction) KeySize() int {
switch cipher {
case CipherCAST5:
return cast5.KeySize
diff --git a/src/pkg/crypto/openpgp/packet/private_key.go b/src/pkg/crypto/openpgp/packet/private_key.go
index 92e7ee422..6f8133d98 100644
--- a/src/pkg/crypto/openpgp/packet/private_key.go
+++ b/src/pkg/crypto/openpgp/packet/private_key.go
@@ -9,6 +9,7 @@ import (
"bytes"
"crypto/cipher"
"crypto/dsa"
+ "crypto/openpgp/elgamal"
"crypto/openpgp/error"
"crypto/openpgp/s2k"
"crypto/rsa"
@@ -181,7 +182,7 @@ func (pk *PrivateKey) Decrypt(passphrase []byte) os.Error {
return nil
}
- key := make([]byte, pk.cipher.keySize())
+ key := make([]byte, pk.cipher.KeySize())
pk.s2k(key, passphrase)
block := pk.cipher.new(key)
cfb := cipher.NewCFBDecrypter(block, pk.iv)
@@ -224,6 +225,8 @@ func (pk *PrivateKey) parsePrivateKey(data []byte) (err os.Error) {
return pk.parseRSAPrivateKey(data)
case PubKeyAlgoDSA:
return pk.parseDSAPrivateKey(data)
+ case PubKeyAlgoElGamal:
+ return pk.parseElGamalPrivateKey(data)
}
panic("impossible")
}
@@ -277,3 +280,22 @@ func (pk *PrivateKey) parseDSAPrivateKey(data []byte) (err os.Error) {
return nil
}
+
+func (pk *PrivateKey) parseElGamalPrivateKey(data []byte) (err os.Error) {
+ pub := pk.PublicKey.PublicKey.(*elgamal.PublicKey)
+ priv := new(elgamal.PrivateKey)
+ priv.PublicKey = *pub
+
+ buf := bytes.NewBuffer(data)
+ x, _, err := readMPI(buf)
+ if err != nil {
+ return
+ }
+
+ priv.X = new(big.Int).SetBytes(x)
+ pk.PrivateKey = priv
+ pk.Encrypted = false
+ pk.encryptedData = nil
+
+ return nil
+}
diff --git a/src/pkg/crypto/openpgp/packet/private_key_test.go b/src/pkg/crypto/openpgp/packet/private_key_test.go
index e941cc735..60eebaa6b 100644
--- a/src/pkg/crypto/openpgp/packet/private_key_test.go
+++ b/src/pkg/crypto/openpgp/packet/private_key_test.go
@@ -8,30 +8,50 @@ import (
"testing"
)
-func TestPrivateKeyRead(t *testing.T) {
- packet, err := Read(readerFromHex(privKeyHex))
- if err != nil {
- t.Error(err)
- return
- }
-
- privKey := packet.(*PrivateKey)
-
- if !privKey.Encrypted {
- t.Error("private key isn't encrypted")
- return
- }
-
- err = privKey.Decrypt([]byte("testing"))
- if err != nil {
- t.Error(err)
- return
- }
+var privateKeyTests = []struct {
+ privateKeyHex string
+ creationTime uint32
+}{
+ {
+ privKeyRSAHex,
+ 0x4cc349a8,
+ },
+ {
+ privKeyElGamalHex,
+ 0x4df9ee1a,
+ },
+}
- if privKey.CreationTime != 0x4cc349a8 || privKey.Encrypted {
- t.Errorf("failed to parse, got: %#v", privKey)
+func TestPrivateKeyRead(t *testing.T) {
+ for i, test := range privateKeyTests {
+ packet, err := Read(readerFromHex(test.privateKeyHex))
+ if err != nil {
+ t.Errorf("#%d: failed to parse: %s", i, err)
+ continue
+ }
+
+ privKey := packet.(*PrivateKey)
+
+ if !privKey.Encrypted {
+ t.Errorf("#%d: private key isn't encrypted", i)
+ continue
+ }
+
+ err = privKey.Decrypt([]byte("testing"))
+ if err != nil {
+ t.Errorf("#%d: failed to decrypt: %s", i, err)
+ continue
+ }
+
+ if privKey.CreationTime != test.creationTime || privKey.Encrypted {
+ t.Errorf("#%d: bad result, got: %#v", i, privKey)
+ }
}
}
// Generated with `gpg --export-secret-keys "Test Key 2"`
-const privKeyHex = "9501fe044cc349a8010400b70ca0010e98c090008d45d1ee8f9113bd5861fd57b88bacb7c68658747663f1e1a3b5a98f32fda6472373c024b97359cd2efc88ff60f77751adfbf6af5e615e6a1408cfad8bf0cea30b0d5f53aa27ad59089ba9b15b7ebc2777a25d7b436144027e3bcd203909f147d0e332b240cf63d3395f5dfe0df0a6c04e8655af7eacdf0011010001fe0303024a252e7d475fd445607de39a265472aa74a9320ba2dac395faa687e9e0336aeb7e9a7397e511b5afd9dc84557c80ac0f3d4d7bfec5ae16f20d41c8c84a04552a33870b930420e230e179564f6d19bb153145e76c33ae993886c388832b0fa042ddda7f133924f3854481533e0ede31d51278c0519b29abc3bf53da673e13e3e1214b52413d179d7f66deee35cac8eacb060f78379d70ef4af8607e68131ff529439668fc39c9ce6dfef8a5ac234d234802cbfb749a26107db26406213ae5c06d4673253a3cbee1fcbae58d6ab77e38d6e2c0e7c6317c48e054edadb5a40d0d48acb44643d998139a8a66bb820be1f3f80185bc777d14b5954b60effe2448a036d565c6bc0b915fcea518acdd20ab07bc1529f561c58cd044f723109b93f6fd99f876ff891d64306b5d08f48bab59f38695e9109c4dec34013ba3153488ce070268381ba923ee1eb77125b36afcb4347ec3478c8f2735b06ef17351d872e577fa95d0c397c88c71b59629a36aec"
+const privKeyRSAHex = "9501fe044cc349a8010400b70ca0010e98c090008d45d1ee8f9113bd5861fd57b88bacb7c68658747663f1e1a3b5a98f32fda6472373c024b97359cd2efc88ff60f77751adfbf6af5e615e6a1408cfad8bf0cea30b0d5f53aa27ad59089ba9b15b7ebc2777a25d7b436144027e3bcd203909f147d0e332b240cf63d3395f5dfe0df0a6c04e8655af7eacdf0011010001fe0303024a252e7d475fd445607de39a265472aa74a9320ba2dac395faa687e9e0336aeb7e9a7397e511b5afd9dc84557c80ac0f3d4d7bfec5ae16f20d41c8c84a04552a33870b930420e230e179564f6d19bb153145e76c33ae993886c388832b0fa042ddda7f133924f3854481533e0ede31d51278c0519b29abc3bf53da673e13e3e1214b52413d179d7f66deee35cac8eacb060f78379d70ef4af8607e68131ff529439668fc39c9ce6dfef8a5ac234d234802cbfb749a26107db26406213ae5c06d4673253a3cbee1fcbae58d6ab77e38d6e2c0e7c6317c48e054edadb5a40d0d48acb44643d998139a8a66bb820be1f3f80185bc777d14b5954b60effe2448a036d565c6bc0b915fcea518acdd20ab07bc1529f561c58cd044f723109b93f6fd99f876ff891d64306b5d08f48bab59f38695e9109c4dec34013ba3153488ce070268381ba923ee1eb77125b36afcb4347ec3478c8f2735b06ef17351d872e577fa95d0c397c88c71b59629a36aec"
+
+// Generated by `gpg --export-secret-keys` followed by a manual extraction of
+// the ElGamal subkey from the packets.
+const privKeyElGamalHex = "9d0157044df9ee1a100400eb8e136a58ec39b582629cdadf830bc64e0a94ed8103ca8bb247b27b11b46d1d25297ef4bcc3071785ba0c0bedfe89eabc5287fcc0edf81ab5896c1c8e4b20d27d79813c7aede75320b33eaeeaa586edc00fd1036c10133e6ba0ff277245d0d59d04b2b3421b7244aca5f4a8d870c6f1c1fbff9e1c26699a860b9504f35ca1d700030503fd1ededd3b840795be6d9ccbe3c51ee42e2f39233c432b831ddd9c4e72b7025a819317e47bf94f9ee316d7273b05d5fcf2999c3a681f519b1234bbfa6d359b4752bd9c3f77d6b6456cde152464763414ca130f4e91d91041432f90620fec0e6d6b5116076c2985d5aeaae13be492b9b329efcaf7ee25120159a0a30cd976b42d7afe030302dae7eb80db744d4960c4df930d57e87fe81412eaace9f900e6c839817a614ddb75ba6603b9417c33ea7b6c93967dfa2bcff3fa3c74a5ce2c962db65b03aece14c96cbd0038fc"
diff --git a/src/pkg/crypto/openpgp/packet/public_key.go b/src/pkg/crypto/openpgp/packet/public_key.go
index 46d365b2a..ba4d481f0 100644
--- a/src/pkg/crypto/openpgp/packet/public_key.go
+++ b/src/pkg/crypto/openpgp/packet/public_key.go
@@ -7,6 +7,7 @@ package packet
import (
"big"
"crypto/dsa"
+ "crypto/openpgp/elgamal"
"crypto/openpgp/error"
"crypto/rsa"
"crypto/sha1"
@@ -69,6 +70,8 @@ func (pk *PublicKey) parse(r io.Reader) (err os.Error) {
err = pk.parseRSA(r)
case PubKeyAlgoDSA:
err = pk.parseDSA(r)
+ case PubKeyAlgoElGamal:
+ err = pk.parseElGamal(r)
default:
err = error.UnsupportedError("public key type: " + strconv.Itoa(int(pk.PubKeyAlgo)))
}
@@ -117,7 +120,7 @@ func (pk *PublicKey) parseRSA(r io.Reader) (err os.Error) {
return
}
-// parseRSA parses DSA public key material from the given Reader. See RFC 4880,
+// parseDSA parses DSA public key material from the given Reader. See RFC 4880,
// section 5.5.2.
func (pk *PublicKey) parseDSA(r io.Reader) (err os.Error) {
pk.p.bytes, pk.p.bitLength, err = readMPI(r)
@@ -146,6 +149,30 @@ func (pk *PublicKey) parseDSA(r io.Reader) (err os.Error) {
return
}
+// parseElGamal parses ElGamal public key material from the given Reader. See
+// RFC 4880, section 5.5.2.
+func (pk *PublicKey) parseElGamal(r io.Reader) (err os.Error) {
+ pk.p.bytes, pk.p.bitLength, err = readMPI(r)
+ if err != nil {
+ return
+ }
+ pk.g.bytes, pk.g.bitLength, err = readMPI(r)
+ if err != nil {
+ return
+ }
+ pk.y.bytes, pk.y.bitLength, err = readMPI(r)
+ if err != nil {
+ return
+ }
+
+ elgamal := new(elgamal.PublicKey)
+ elgamal.P = new(big.Int).SetBytes(pk.p.bytes)
+ elgamal.G = new(big.Int).SetBytes(pk.g.bytes)
+ elgamal.Y = new(big.Int).SetBytes(pk.y.bytes)
+ pk.PublicKey = elgamal
+ return
+}
+
// SerializeSignaturePrefix writes the prefix for this public key to the given Writer.
// The prefix is used when calculating a signature over this public key. See
// RFC 4880, section 5.2.4.
@@ -160,6 +187,10 @@ func (pk *PublicKey) SerializeSignaturePrefix(h hash.Hash) {
pLength += 2 + uint16(len(pk.q.bytes))
pLength += 2 + uint16(len(pk.g.bytes))
pLength += 2 + uint16(len(pk.y.bytes))
+ case PubKeyAlgoElGamal:
+ pLength += 2 + uint16(len(pk.p.bytes))
+ pLength += 2 + uint16(len(pk.g.bytes))
+ pLength += 2 + uint16(len(pk.y.bytes))
default:
panic("unknown public key algorithm")
}
@@ -180,6 +211,12 @@ func (pk *PublicKey) Serialize(w io.Writer) (err os.Error) {
length += 2 + len(pk.q.bytes)
length += 2 + len(pk.g.bytes)
length += 2 + len(pk.y.bytes)
+ case PubKeyAlgoElGamal:
+ length += 2 + len(pk.p.bytes)
+ length += 2 + len(pk.g.bytes)
+ length += 2 + len(pk.y.bytes)
+ default:
+ panic("unknown public key algorithm")
}
err = serializeHeader(w, packetTypePublicKey, length)
@@ -210,13 +247,15 @@ func (pk *PublicKey) serializeWithoutHeaders(w io.Writer) (err os.Error) {
return writeMPIs(w, pk.n, pk.e)
case PubKeyAlgoDSA:
return writeMPIs(w, pk.p, pk.q, pk.g, pk.y)
+ case PubKeyAlgoElGamal:
+ return writeMPIs(w, pk.p, pk.g, pk.y)
}
return error.InvalidArgumentError("bad public-key algorithm")
}
// CanSign returns true iff this public key can generate signatures
func (pk *PublicKey) CanSign() bool {
- return pk.PubKeyAlgo != PubKeyAlgoRSAEncryptOnly && pk.PubKeyAlgo != PubKeyAlgoElgamal
+ return pk.PubKeyAlgo != PubKeyAlgoRSAEncryptOnly && pk.PubKeyAlgo != PubKeyAlgoElGamal
}
// VerifySignature returns nil iff sig is a valid signature, made by this
diff --git a/src/pkg/crypto/openpgp/packet/signature.go b/src/pkg/crypto/openpgp/packet/signature.go
index 3169bac1e..123c99fb2 100644
--- a/src/pkg/crypto/openpgp/packet/signature.go
+++ b/src/pkg/crypto/openpgp/packet/signature.go
@@ -177,7 +177,11 @@ const (
// parseSignatureSubpacket parses a single subpacket. len(subpacket) is >= 1.
func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (rest []byte, err os.Error) {
// RFC 4880, section 5.2.3.1
- var length uint32
+ var (
+ length uint32
+ packetType byte
+ isCritical bool
+ )
switch {
case subpacket[0] < 192:
length = uint32(subpacket[0])
@@ -207,8 +211,8 @@ func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (r
err = error.StructuralError("zero length signature subpacket")
return
}
- packetType := subpacket[0] & 0x7f
- isCritial := subpacket[0]&0x80 == 0x80
+ packetType = subpacket[0] & 0x7f
+ isCritical = subpacket[0]&0x80 == 0x80
subpacket = subpacket[1:]
switch signatureSubpacketType(packetType) {
case creationTimeSubpacket:
@@ -309,7 +313,7 @@ func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (r
}
default:
- if isCritial {
+ if isCritical {
err = error.UnsupportedError("unknown critical signature subpacket type " + strconv.Itoa(int(packetType)))
return
}
diff --git a/src/pkg/crypto/openpgp/packet/symmetric_key_encrypted.go b/src/pkg/crypto/openpgp/packet/symmetric_key_encrypted.go
index 25d264acf..ad4f1d621 100644
--- a/src/pkg/crypto/openpgp/packet/symmetric_key_encrypted.go
+++ b/src/pkg/crypto/openpgp/packet/symmetric_key_encrypted.go
@@ -42,7 +42,7 @@ func (ske *SymmetricKeyEncrypted) parse(r io.Reader) (err os.Error) {
}
ske.CipherFunc = CipherFunction(buf[1])
- if ske.CipherFunc.keySize() == 0 {
+ if ske.CipherFunc.KeySize() == 0 {
return error.UnsupportedError("unknown cipher: " + strconv.Itoa(int(buf[1])))
}
@@ -78,7 +78,7 @@ func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) os.Error {
return nil
}
- key := make([]byte, ske.CipherFunc.keySize())
+ key := make([]byte, ske.CipherFunc.KeySize())
ske.s2k(key, passphrase)
if len(ske.encryptedKey) == 0 {
@@ -109,7 +109,7 @@ func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) os.Error {
// given passphrase. The session key is returned and must be passed to
// SerializeSymmetricallyEncrypted.
func SerializeSymmetricKeyEncrypted(w io.Writer, rand io.Reader, passphrase []byte, cipherFunc CipherFunction) (key []byte, err os.Error) {
- keySize := cipherFunc.keySize()
+ keySize := cipherFunc.KeySize()
if keySize == 0 {
return nil, error.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc)))
}
diff --git a/src/pkg/crypto/openpgp/packet/symmetrically_encrypted.go b/src/pkg/crypto/openpgp/packet/symmetrically_encrypted.go
index 236c36774..e33c9f3a0 100644
--- a/src/pkg/crypto/openpgp/packet/symmetrically_encrypted.go
+++ b/src/pkg/crypto/openpgp/packet/symmetrically_encrypted.go
@@ -47,7 +47,7 @@ func (se *SymmetricallyEncrypted) parse(r io.Reader) os.Error {
// packet can be read. An incorrect key can, with high probability, be detected
// immediately and this will result in a KeyIncorrect error being returned.
func (se *SymmetricallyEncrypted) Decrypt(c CipherFunction, key []byte) (io.ReadCloser, os.Error) {
- keySize := c.keySize()
+ keySize := c.KeySize()
if keySize == 0 {
return nil, error.UnsupportedError("unknown cipher: " + strconv.Itoa(int(c)))
}
@@ -255,7 +255,7 @@ func (c noOpCloser) Close() os.Error {
// to w and returns a WriteCloser to which the to-be-encrypted packets can be
// written.
func SerializeSymmetricallyEncrypted(w io.Writer, c CipherFunction, key []byte) (contents io.WriteCloser, err os.Error) {
- if c.keySize() != len(key) {
+ if c.KeySize() != len(key) {
return nil, error.InvalidArgumentError("SymmetricallyEncrypted.Serialize: bad key length")
}
writeCloser := noOpCloser{w}
diff --git a/src/pkg/crypto/openpgp/packet/symmetrically_encrypted_test.go b/src/pkg/crypto/openpgp/packet/symmetrically_encrypted_test.go
index ba5606e6c..1054fc2f9 100644
--- a/src/pkg/crypto/openpgp/packet/symmetrically_encrypted_test.go
+++ b/src/pkg/crypto/openpgp/packet/symmetrically_encrypted_test.go
@@ -81,7 +81,7 @@ const mdcPlaintextHex = "a302789c3b2d93c4e0eb9aba22283539b3203335af44a134afb800c
func TestSerialize(t *testing.T) {
buf := bytes.NewBuffer(nil)
c := CipherAES128
- key := make([]byte, c.keySize())
+ key := make([]byte, c.KeySize())
w, err := SerializeSymmetricallyEncrypted(buf, c, key)
if err != nil {
diff --git a/src/pkg/crypto/openpgp/read.go b/src/pkg/crypto/openpgp/read.go
index 46fcde363..683014752 100644
--- a/src/pkg/crypto/openpgp/read.go
+++ b/src/pkg/crypto/openpgp/read.go
@@ -10,7 +10,6 @@ import (
"crypto/openpgp/armor"
"crypto/openpgp/error"
"crypto/openpgp/packet"
- "crypto/rsa"
_ "crypto/sha256"
"hash"
"io"
@@ -57,7 +56,6 @@ type MessageDetails struct {
// been consumed. Once EOF has been seen, the following fields are
// valid. (An authentication code failure is reported as a
// SignatureError error when reading from UnverifiedBody.)
-
SignatureError os.Error // nil if the signature is good.
Signature *packet.Signature // the signature packet itself.
@@ -112,7 +110,10 @@ ParsePackets:
case *packet.EncryptedKey:
// This packet contains the decryption key encrypted to a public key.
md.EncryptedToKeyIds = append(md.EncryptedToKeyIds, p.KeyId)
- if p.Algo != packet.PubKeyAlgoRSA && p.Algo != packet.PubKeyAlgoRSAEncryptOnly {
+ switch p.Algo {
+ case packet.PubKeyAlgoRSA, packet.PubKeyAlgoRSAEncryptOnly, packet.PubKeyAlgoElGamal:
+ break
+ default:
continue
}
var keys []Key
@@ -155,7 +156,7 @@ FindKey:
}
if !pk.key.PrivateKey.Encrypted {
if len(pk.encryptedKey.Key) == 0 {
- pk.encryptedKey.DecryptRSA(pk.key.PrivateKey.PrivateKey.(*rsa.PrivateKey))
+ pk.encryptedKey.Decrypt(pk.key.PrivateKey)
}
if len(pk.encryptedKey.Key) == 0 {
continue
diff --git a/src/pkg/crypto/openpgp/read_test.go b/src/pkg/crypto/openpgp/read_test.go
index a040b5b1b..7182e94b5 100644
--- a/src/pkg/crypto/openpgp/read_test.go
+++ b/src/pkg/crypto/openpgp/read_test.go
@@ -102,49 +102,71 @@ func TestTextSignedMessage(t *testing.T) {
checkSignedMessage(t, signedTextMessageHex, signedTextInput)
}
-func TestSignedEncryptedMessage(t *testing.T) {
- expected := "Signed and encrypted message\n"
- kring, _ := ReadKeyRing(readerFromHex(testKeys1And2PrivateHex))
- prompt := func(keys []Key, symmetric bool) ([]byte, os.Error) {
- if symmetric {
- t.Errorf("prompt: message was marked as symmetrically encrypted")
- return nil, error.KeyIncorrectError
- }
+var signedEncryptedMessageTests = []struct {
+ keyRingHex string
+ messageHex string
+ signedByKeyId uint64
+ encryptedToKeyId uint64
+}{
+ {
+ testKeys1And2PrivateHex,
+ signedEncryptedMessageHex,
+ 0xa34d7e18c20c31bb,
+ 0x2a67d68660df41c7,
+ },
+ {
+ dsaElGamalTestKeysHex,
+ signedEncryptedMessage2Hex,
+ 0x33af447ccd759b09,
+ 0xcf6a7abcd43e3673,
+ },
+}
- if len(keys) == 0 {
- t.Error("prompt: no keys requested")
- return nil, error.KeyIncorrectError
+func TestSignedEncryptedMessage(t *testing.T) {
+ for i, test := range signedEncryptedMessageTests {
+ expected := "Signed and encrypted message\n"
+ kring, _ := ReadKeyRing(readerFromHex(test.keyRingHex))
+ prompt := func(keys []Key, symmetric bool) ([]byte, os.Error) {
+ if symmetric {
+ t.Errorf("prompt: message was marked as symmetrically encrypted")
+ return nil, error.KeyIncorrectError
+ }
+
+ if len(keys) == 0 {
+ t.Error("prompt: no keys requested")
+ return nil, error.KeyIncorrectError
+ }
+
+ err := keys[0].PrivateKey.Decrypt([]byte("passphrase"))
+ if err != nil {
+ t.Errorf("prompt: error decrypting key: %s", err)
+ return nil, error.KeyIncorrectError
+ }
+
+ return nil, nil
}
- err := keys[0].PrivateKey.Decrypt([]byte("passphrase"))
+ md, err := ReadMessage(readerFromHex(test.messageHex), kring, prompt)
if err != nil {
- t.Errorf("prompt: error decrypting key: %s", err)
- return nil, error.KeyIncorrectError
+ t.Errorf("#%d: error reading message: %s", i, err)
+ return
}
- return nil, nil
- }
-
- md, err := ReadMessage(readerFromHex(signedEncryptedMessageHex), kring, prompt)
- if err != nil {
- t.Errorf("error reading message: %s", err)
- return
- }
-
- if !md.IsSigned || md.SignedByKeyId != 0xa34d7e18c20c31bb || md.SignedBy == nil || !md.IsEncrypted || md.IsSymmetricallyEncrypted || len(md.EncryptedToKeyIds) == 0 || md.EncryptedToKeyIds[0] != 0x2a67d68660df41c7 {
- t.Errorf("bad MessageDetails: %#v", md)
- }
+ if !md.IsSigned || md.SignedByKeyId != test.signedByKeyId || md.SignedBy == nil || !md.IsEncrypted || md.IsSymmetricallyEncrypted || len(md.EncryptedToKeyIds) == 0 || md.EncryptedToKeyIds[0] != test.encryptedToKeyId {
+ t.Errorf("#%d: bad MessageDetails: %#v", i, md)
+ }
- contents, err := ioutil.ReadAll(md.UnverifiedBody)
- if err != nil {
- t.Errorf("error reading UnverifiedBody: %s", err)
- }
- if string(contents) != expected {
- t.Errorf("bad UnverifiedBody got:%s want:%s", string(contents), expected)
- }
+ contents, err := ioutil.ReadAll(md.UnverifiedBody)
+ if err != nil {
+ t.Errorf("#%d: error reading UnverifiedBody: %s", i, err)
+ }
+ if string(contents) != expected {
+ t.Errorf("#%d: bad UnverifiedBody got:%s want:%s", i, string(contents), expected)
+ }
- if md.SignatureError != nil || md.Signature == nil {
- t.Errorf("failed to validate: %s", md.SignatureError)
+ if md.SignatureError != nil || md.Signature == nil {
+ t.Errorf("#%d: failed to validate: %s", i, md.SignatureError)
+ }
}
}
@@ -265,12 +287,16 @@ const testKeys1And2Hex = "988d044d3c5c10010400b1d13382944bd5aba23a4312968b5095d1
const testKeys1And2PrivateHex = "9501d8044d3c5c10010400b1d13382944bd5aba23a4312968b5095d14f947f600eb478e14a6fcb16b0e0cac764884909c020bc495cfcc39a935387c661507bdb236a0612fb582cac3af9b29cc2c8c70090616c41b662f4da4c1201e195472eb7f4ae1ccbcbf9940fe21d985e379a5563dde5b9a23d35f1cfaa5790da3b79db26f23695107bfaca8e7b5bcd00110100010003ff4d91393b9a8e3430b14d6209df42f98dc927425b881f1209f319220841273a802a97c7bdb8b3a7740b3ab5866c4d1d308ad0d3a79bd1e883aacf1ac92dfe720285d10d08752a7efe3c609b1d00f17f2805b217be53999a7da7e493bfc3e9618fd17018991b8128aea70a05dbce30e4fbe626aa45775fa255dd9177aabf4df7cf0200c1ded12566e4bc2bb590455e5becfb2e2c9796482270a943343a7835de41080582c2be3caf5981aa838140e97afa40ad652a0b544f83eb1833b0957dce26e47b0200eacd6046741e9ce2ec5beb6fb5e6335457844fb09477f83b050a96be7da043e17f3a9523567ed40e7a521f818813a8b8a72209f1442844843ccc7eb9805442570200bdafe0438d97ac36e773c7162028d65844c4d463e2420aa2228c6e50dc2743c3d6c72d0d782a5173fe7be2169c8a9f4ef8a7cf3e37165e8c61b89c346cdc6c1799d2b41054657374204b6579203120285253412988b804130102002205024d3c5c10021b03060b090807030206150802090a0b0416020301021e01021780000a0910a34d7e18c20c31bbb5b304009cc45fe610b641a2c146331be94dade0a396e73ca725e1b25c21708d9cab46ecca5ccebc23055879df8f99eea39b377962a400f2ebdc36a7c99c333d74aeba346315137c3ff9d0a09b0273299090343048afb8107cf94cbd1400e3026f0ccac7ecebbc4d78588eb3e478fe2754d3ca664bcf3eac96ca4a6b0c8d7df5102f60f6b00200009d01d8044d3c5c10010400b201df61d67487301f11879d514f4248ade90c8f68c7af1284c161098de4c28c2850f1ec7b8e30f959793e571542ffc6532189409cb51c3d30dad78c4ad5165eda18b20d9826d8707d0f742e2ab492103a85bbd9ddf4f5720f6de7064feb0d39ee002219765bb07bcfb8b877f47abe270ddeda4f676108cecb6b9bb2ad484a4f00110100010003fd17a7490c22a79c59281fb7b20f5e6553ec0c1637ae382e8adaea295f50241037f8997cf42c1ce26417e015091451b15424b2c59eb8d4161b0975630408e394d3b00f88d4b4e18e2cc85e8251d4753a27c639c83f5ad4a571c4f19d7cd460b9b73c25ade730c99df09637bd173d8e3e981ac64432078263bb6dc30d3e974150dd0200d0ee05be3d4604d2146fb0457f31ba17c057560785aa804e8ca5530a7cd81d3440d0f4ba6851efcfd3954b7e68908fc0ba47f7ac37bf559c6c168b70d3a7c8cd0200da1c677c4bce06a068070f2b3733b0a714e88d62aa3f9a26c6f5216d48d5c2b5624144f3807c0df30be66b3268eeeca4df1fbded58faf49fc95dc3c35f134f8b01fd1396b6c0fc1b6c4f0eb8f5e44b8eace1e6073e20d0b8bc5385f86f1cf3f050f66af789f3ef1fc107b7f4421e19e0349c730c68f0a226981f4e889054fdb4dc149e8e889f04180102000905024d3c5c10021b0c000a0910a34d7e18c20c31bb1a03040085c8d62e16d05dc4e9dad64953c8a2eed8b6c12f92b1575eeaa6dcf7be9473dd5b24b37b6dffbb4e7c99ed1bd3cb11634be19b3e6e207bed7505c7ca111ccf47cb323bf1f8851eb6360e8034cbff8dd149993c959de89f8f77f38e7e98b8e3076323aa719328e2b408db5ec0d03936efd57422ba04f925cdc7b4c1af7590e40ab00200009501fe044d3c5c33010400b488c3e5f83f4d561f317817538d9d0397981e9aef1321ca68ebfae1cf8b7d388e19f4b5a24a82e2fbbf1c6c26557a6c5845307a03d815756f564ac7325b02bc83e87d5480a8fae848f07cb891f2d51ce7df83dcafdc12324517c86d472cc0ee10d47a68fd1d9ae49a6c19bbd36d82af597a0d88cc9c49de9df4e696fc1f0b5d0011010001fe030302e9030f3c783e14856063f16938530e148bc57a7aa3f3e4f90df9dceccdc779bc0835e1ad3d006e4a8d7b36d08b8e0de5a0d947254ecfbd22037e6572b426bcfdc517796b224b0036ff90bc574b5509bede85512f2eefb520fb4b02aa523ba739bff424a6fe81c5041f253f8d757e69a503d3563a104d0d49e9e890b9d0c26f96b55b743883b472caa7050c4acfd4a21f875bdf1258d88bd61224d303dc9df77f743137d51e6d5246b88c406780528fd9a3e15bab5452e5b93970d9dcc79f48b38651b9f15bfbcf6da452837e9cc70683d1bdca94507870f743e4ad902005812488dd342f836e72869afd00ce1850eea4cfa53ce10e3608e13d3c149394ee3cbd0e23d018fcbcb6e2ec5a1a22972d1d462ca05355d0d290dd2751e550d5efb38c6c89686344df64852bf4ff86638708f644e8ec6bd4af9b50d8541cb91891a431326ab2e332faa7ae86cfb6e0540aa63160c1e5cdd5a4add518b303fff0a20117c6bc77f7cfbaf36b04c865c6c2b42754657374204b6579203220285253412c20656e637279707465642070726976617465206b65792988b804130102002205024d3c5c33021b03060b090807030206150802090a0b0416020301021e01021780000a0910d4984f961e35246b98940400908a73b6a6169f700434f076c6c79015a49bee37130eaf23aaa3cfa9ce60bfe4acaa7bc95f1146ada5867e0079babb38804891f4f0b8ebca57a86b249dee786161a755b7a342e68ccf3f78ed6440a93a6626beb9a37aa66afcd4f888790cb4bb46d94a4ae3eb3d7d3e6b00f6bfec940303e89ec5b32a1eaaacce66497d539328b00200009d01fe044d3c5c33010400a4e913f9442abcc7f1804ccab27d2f787ffa592077ca935a8bb23165bd8d57576acac647cc596b2c3f814518cc8c82953c7a4478f32e0cf645630a5ba38d9618ef2bc3add69d459ae3dece5cab778938d988239f8c5ae437807075e06c828019959c644ff05ef6a5a1dab72227c98e3a040b0cf219026640698d7a13d8538a570011010001fe030302e9030f3c783e148560f936097339ae381d63116efcf802ff8b1c9360767db5219cc987375702a4123fd8657d3e22700f23f95020d1b261eda5257e9a72f9a918e8ef22dd5b3323ae03bbc1923dd224db988cadc16acc04b120a9f8b7e84da9716c53e0334d7b66586ddb9014df604b41be1e960dcfcbc96f4ed150a1a0dd070b9eb14276b9b6be413a769a75b519a53d3ecc0c220e85cd91ca354d57e7344517e64b43b6e29823cbd87eae26e2b2e78e6dedfbb76e3e9f77bcb844f9a8932eb3db2c3f9e44316e6f5d60e9e2a56e46b72abe6b06dc9a31cc63f10023d1f5e12d2a3ee93b675c96f504af0001220991c88db759e231b3320dcedf814dcf723fd9857e3d72d66a0f2af26950b915abdf56c1596f46a325bf17ad4810d3535fb02a259b247ac3dbd4cc3ecf9c51b6c07cebb009c1506fba0a89321ec8683e3fd009a6e551d50243e2d5092fefb3321083a4bad91320dc624bd6b5dddf93553e3d53924c05bfebec1fb4bd47e89a1a889f04180102000905024d3c5c33021b0c000a0910d4984f961e35246b26c703ff7ee29ef53bc1ae1ead533c408fa136db508434e233d6e62be621e031e5940bbd4c08142aed0f82217e7c3e1ec8de574bc06ccf3c36633be41ad78a9eacd209f861cae7b064100758545cc9dd83db71806dc1cfd5fb9ae5c7474bba0c19c44034ae61bae5eca379383339dece94ff56ff7aa44a582f3e5c38f45763af577c0934b0020000"
+const dsaElGamalTestKeysHex = "9501e1044dfcb16a110400aa3e5c1a1f43dd28c2ffae8abf5cfce555ee874134d8ba0a0f7b868ce2214beddc74e5e1e21ded354a95d18acdaf69e5e342371a71fbb9093162e0c5f3427de413a7f2c157d83f5cd2f9d791256dc4f6f0e13f13c3302af27f2384075ab3021dff7a050e14854bbde0a1094174855fc02f0bae8e00a340d94a1f22b32e48485700a0cec672ac21258fb95f61de2ce1af74b2c4fa3e6703ff698edc9be22c02ae4d916e4fa223f819d46582c0516235848a77b577ea49018dcd5e9e15cff9dbb4663a1ae6dd7580fa40946d40c05f72814b0f88481207e6c0832c3bded4853ebba0a7e3bd8e8c66df33d5a537cd4acf946d1080e7a3dcea679cb2b11a72a33a2b6a9dc85f466ad2ddf4c3db6283fa645343286971e3dd700703fc0c4e290d45767f370831a90187e74e9972aae5bff488eeff7d620af0362bfb95c1a6c3413ab5d15a2e4139e5d07a54d72583914661ed6a87cce810be28a0aa8879a2dd39e52fb6fe800f4f181ac7e328f740cde3d09a05cecf9483e4cca4253e60d4429ffd679d9996a520012aad119878c941e3cf151459873bdfc2a9563472fe0303027a728f9feb3b864260a1babe83925ce794710cfd642ee4ae0e5b9d74cee49e9c67b6cd0ea5dfbb582132195a121356a1513e1bca73e5b80c58c7ccb4164453412f456c47616d616c2054657374204b65792031886204131102002205024dfcb16a021b03060b090807030206150802090a0b0416020301021e01021780000a091033af447ccd759b09fadd00a0b8fd6f5a790bad7e9f2dbb7632046dc4493588db009c087c6a9ba9f7f49fab221587a74788c00db4889ab00200009d0157044dfcb16a1004008dec3f9291205255ccff8c532318133a6840739dd68b03ba942676f9038612071447bf07d00d559c5c0875724ea16a4c774f80d8338b55fca691a0522e530e604215b467bbc9ccfd483a1da99d7bc2648b4318fdbd27766fc8bfad3fddb37c62b8ae7ccfe9577e9b8d1e77c1d417ed2c2ef02d52f4da11600d85d3229607943700030503ff506c94c87c8cab778e963b76cf63770f0a79bf48fb49d3b4e52234620fc9f7657f9f8d56c96a2b7c7826ae6b57ebb2221a3fe154b03b6637cea7e6d98e3e45d87cf8dc432f723d3d71f89c5192ac8d7290684d2c25ce55846a80c9a7823f6acd9bb29fa6cd71f20bc90eccfca20451d0c976e460e672b000df49466408d527affe0303027a728f9feb3b864260abd761730327bca2aaa4ea0525c175e92bf240682a0e83b226f97ecb2e935b62c9a133858ce31b271fa8eb41f6a1b3cd72a63025ce1a75ee4180dcc284884904181102000905024dfcb16a021b0c000a091033af447ccd759b09dd0b009e3c3e7296092c81bee5a19929462caaf2fff3ae26009e218c437a2340e7ea628149af1ec98ec091a43992b00200009501e1044dfcb1be1104009f61faa61aa43df75d128cbe53de528c4aec49ce9360c992e70c77072ad5623de0a3a6212771b66b39a30dad6781799e92608316900518ec01184a85d872365b7d2ba4bacfb5882ea3c2473d3750dc6178cc1cf82147fb58caa28b28e9f12f6d1efcb0534abed644156c91cca4ab78834268495160b2400bc422beb37d237c2300a0cac94911b6d493bda1e1fbc6feeca7cb7421d34b03fe22cec6ccb39675bb7b94a335c2b7be888fd3906a1125f33301d8aa6ec6ee6878f46f73961c8d57a3e9544d8ef2a2cbfd4d52da665b1266928cfe4cb347a58c412815f3b2d2369dec04b41ac9a71cc9547426d5ab941cccf3b18575637ccfb42df1a802df3cfe0a999f9e7109331170e3a221991bf868543960f8c816c28097e503fe319db10fb98049f3a57d7c80c420da66d56f3644371631fad3f0ff4040a19a4fedc2d07727a1b27576f75a4d28c47d8246f27071e12d7a8de62aad216ddbae6aa02efd6b8a3e2818cda48526549791ab277e447b3a36c57cefe9b592f5eab73959743fcc8e83cbefec03a329b55018b53eec196765ae40ef9e20521a603c551efe0303020950d53a146bf9c66034d00c23130cce95576a2ff78016ca471276e8227fb30b1ffbd92e61804fb0c3eff9e30b1a826ee8f3e4730b4d86273ca977b4164453412f456c47616d616c2054657374204b65792032886204131102002205024dfcb1be021b03060b090807030206150802090a0b0416020301021e01021780000a0910a86bf526325b21b22bd9009e34511620415c974750a20df5cb56b182f3b48e6600a0a9466cb1a1305a84953445f77d461593f1d42bc1b00200009d0157044dfcb1be1004009565a951da1ee87119d600c077198f1c1bceb0f7aa54552489298e41ff788fa8f0d43a69871f0f6f77ebdfb14a4260cf9fbeb65d5844b4272a1904dd95136d06c3da745dc46327dd44a0f16f60135914368c8039a34033862261806bb2c5ce1152e2840254697872c85441ccb7321431d75a747a4bfb1d2c66362b51ce76311700030503fc0ea76601c196768070b7365a200e6ddb09307f262d5f39eec467b5f5784e22abdf1aa49226f59ab37cb49969d8f5230ea65caf56015abda62604544ed526c5c522bf92bed178a078789f6c807b6d34885688024a5bed9e9f8c58d11d4b82487b44c5f470c5606806a0443b79cadb45e0f897a561a53f724e5349b9267c75ca17fe0303020950d53a146bf9c660bc5f4ce8f072465e2d2466434320c1e712272fafc20e342fe7608101580fa1a1a367e60486a7cd1246b7ef5586cf5e10b32762b710a30144f12dd17dd4884904181102000905024dfcb1be021b0c000a0910a86bf526325b21b2904c00a0b2b66b4b39ccffda1d10f3ea8d58f827e30a8b8e009f4255b2d8112a184e40cde43a34e8655ca7809370b0020000"
+
const signedMessageHex = "a3019bc0cbccc0c4b8d8b74ee2108fe16ec6d3ca490cbe362d3f8333d3f352531472538b8b13d353b97232f352158c20943157c71c16064626063656269052062e4e01987e9b6fccff4b7df3a34c534b23e679cbec3bc0f8f6e64dfb4b55fe3f8efa9ce110ddb5cd79faf1d753c51aecfa669f7e7aa043436596cccc3359cb7dd6bbe9ecaa69e5989d9e57209571edc0b2fa7f57b9b79a64ee6e99ce1371395fee92fec2796f7b15a77c386ff668ee27f6d38f0baa6c438b561657377bf6acff3c5947befd7bf4c196252f1d6e5c524d0300"
const signedTextMessageHex = "a3019bc0cbccc8c4b8d8b74ee2108fe16ec6d36a250cbece0c178233d3f352531472538b8b13d35379b97232f352158ca0b4312f57c71c1646462606365626906a062e4e019811591798ff99bf8afee860b0d8a8c2a85c3387e3bcf0bb3b17987f2bbcfab2aa526d930cbfd3d98757184df3995c9f3e7790e36e3e9779f06089d4c64e9e47dd6202cb6e9bc73c5d11bb59fbaf89d22d8dc7cf199ddf17af96e77c5f65f9bbed56f427bd8db7af37f6c9984bf9385efaf5f184f986fb3e6adb0ecfe35bbf92d16a7aa2a344fb0bc52fb7624f0200"
const signedEncryptedMessageHex = "848c032a67d68660df41c70103ff5789d0de26b6a50c985a02a13131ca829c413a35d0e6fa8d6842599252162808ac7439c72151c8c6183e76923fe3299301414d0c25a2f06a2257db3839e7df0ec964773f6e4c4ac7ff3b48c444237166dd46ba8ff443a5410dc670cb486672fdbe7c9dfafb75b4fea83af3a204fe2a7dfa86bd20122b4f3d2646cbeecb8f7be8d2c03b018bd210b1d3791e1aba74b0f1034e122ab72e760492c192383cf5e20b5628bd043272d63df9b923f147eb6091cd897553204832aba48fec54aa447547bb16305a1024713b90e77fd0065f1918271947549205af3c74891af22ee0b56cd29bfec6d6e351901cd4ab3ece7c486f1e32a792d4e474aed98ee84b3f591c7dff37b64e0ecd68fd036d517e412dcadf85840ce184ad7921ad446c4ee28db80447aea1ca8d4f574db4d4e37688158ddd19e14ee2eab4873d46947d65d14a23e788d912cf9a19624ca7352469b72a83866b7c23cb5ace3deab3c7018061b0ba0f39ed2befe27163e5083cf9b8271e3e3d52cc7ad6e2a3bd81d4c3d7022f8d"
+const signedEncryptedMessage2Hex = "85010e03cf6a7abcd43e36731003fb057f5495b79db367e277cdbe4ab90d924ddee0c0381494112ff8c1238fb0184af35d1731573b01bc4c55ecacd2aafbe2003d36310487d1ecc9ac994f3fada7f9f7f5c3a64248ab7782906c82c6ff1303b69a84d9a9529c31ecafbcdb9ba87e05439897d87e8a2a3dec55e14df19bba7f7bd316291c002ae2efd24f83f9e3441203fc081c0c23dc3092a454ca8a082b27f631abf73aca341686982e8fbda7e0e7d863941d68f3de4a755c2964407f4b5e0477b3196b8c93d551dd23c8beef7d0f03fbb1b6066f78907faf4bf1677d8fcec72651124080e0b7feae6b476e72ab207d38d90b958759fdedfc3c6c35717c9dbfc979b3cfbbff0a76d24a5e57056bb88acbd2a901ef64bc6e4db02adc05b6250ff378de81dca18c1910ab257dff1b9771b85bb9bbe0a69f5989e6d1710a35e6dfcceb7d8fb5ccea8db3932b3d9ff3fe0d327597c68b3622aec8e3716c83a6c93f497543b459b58ba504ed6bcaa747d37d2ca746fe49ae0a6ce4a8b694234e941b5159ff8bd34b9023da2814076163b86f40eed7c9472f81b551452d5ab87004a373c0172ec87ea6ce42ccfa7dbdad66b745496c4873d8019e8c28d6b3"
+
const symmetricallyEncryptedCompressedHex = "8c0d04030302eb4a03808145d0d260c92f714339e13de5a79881216431925bf67ee2898ea61815f07894cd0703c50d0a76ef64d482196f47a8bc729af9b80bb6"
const dsaTestKeyHex = "9901a2044d6c49de110400cb5ce438cf9250907ac2ba5bf6547931270b89f7c4b53d9d09f4d0213a5ef2ec1f26806d3d259960f872a4a102ef1581ea3f6d6882d15134f21ef6a84de933cc34c47cc9106efe3bd84c6aec12e78523661e29bc1a61f0aab17fa58a627fd5fd33f5149153fbe8cd70edf3d963bc287ef875270ff14b5bfdd1bca4483793923b00a0fe46d76cb6e4cbdc568435cd5480af3266d610d303fe33ae8273f30a96d4d34f42fa28ce1112d425b2e3bf7ea553d526e2db6b9255e9dc7419045ce817214d1a0056dbc8d5289956a4b1b69f20f1105124096e6a438f41f2e2495923b0f34b70642607d45559595c7fe94d7fa85fc41bf7d68c1fd509ebeaa5f315f6059a446b9369c277597e4f474a9591535354c7e7f4fd98a08aa60400b130c24ff20bdfbf683313f5daebf1c9b34b3bdadfc77f2ddd72ee1fb17e56c473664bc21d66467655dd74b9005e3a2bacce446f1920cd7017231ae447b67036c9b431b8179deacd5120262d894c26bc015bffe3d827ba7087ad9b700d2ca1f6d16cc1786581e5dd065f293c31209300f9b0afcc3f7c08dd26d0a22d87580b4db41054657374204b65792033202844534129886204131102002205024d6c49de021b03060b090807030206150802090a0b0416020301021e01021780000a0910338934250ccc03607e0400a0bdb9193e8a6b96fc2dfc108ae848914b504481f100a09c4dc148cb693293a67af24dd40d2b13a9e36794"
diff --git a/src/pkg/crypto/openpgp/write.go b/src/pkg/crypto/openpgp/write.go
index 48c86f604..9884472ce 100644
--- a/src/pkg/crypto/openpgp/write.go
+++ b/src/pkg/crypto/openpgp/write.go
@@ -9,10 +9,13 @@ import (
"crypto/openpgp/armor"
"crypto/openpgp/error"
"crypto/openpgp/packet"
+ "crypto/openpgp/s2k"
"crypto/rand"
_ "crypto/sha256"
+ "hash"
"io"
"os"
+ "strconv"
"time"
)
@@ -98,7 +101,7 @@ type FileHints struct {
}
// SymmetricallyEncrypt acts like gpg -c: it encrypts a file with a passphrase.
-// The resulting WriteCloser MUST be closed after the contents of the file have
+// The resulting WriteCloser must be closed after the contents of the file have
// been written.
func SymmetricallyEncrypt(ciphertext io.Writer, passphrase []byte, hints *FileHints) (plaintext io.WriteCloser, err os.Error) {
if hints == nil {
@@ -115,3 +118,191 @@ func SymmetricallyEncrypt(ciphertext io.Writer, passphrase []byte, hints *FileHi
}
return packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, hints.EpochSeconds)
}
+
+// intersectPreferences mutates and returns a prefix of a that contains only
+// the values in the intersection of a and b. The order of a is preserved.
+func intersectPreferences(a []uint8, b []uint8) (intersection []uint8) {
+ var j int
+ for _, v := range a {
+ for _, v2 := range b {
+ if v == v2 {
+ a[j] = v
+ j++
+ break
+ }
+ }
+ }
+
+ return a[:j]
+}
+
+func hashToHashId(h crypto.Hash) uint8 {
+ v, ok := s2k.HashToHashId(h)
+ if !ok {
+ panic("tried to convert unknown hash")
+ }
+ return v
+}
+
+// Encrypt encrypts a message to a number of recipients and, optionally, signs
+// it. hints contains optional information, that is also encrypted, that aids
+// the recipients in processing the message. The resulting WriteCloser must
+// be closed after the contents of the file have been written.
+func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHints) (plaintext io.WriteCloser, err os.Error) {
+ var signer *packet.PrivateKey
+ if signed != nil {
+ signer = signed.signingKey().PrivateKey
+ if signer == nil || signer.Encrypted {
+ return nil, error.InvalidArgumentError("signing key must be decrypted")
+ }
+ }
+
+ // These are the possible ciphers that we'll use for the message.
+ candidateCiphers := []uint8{
+ uint8(packet.CipherAES128),
+ uint8(packet.CipherAES256),
+ uint8(packet.CipherCAST5),
+ }
+ // These are the possible hash functions that we'll use for the signature.
+ candidateHashes := []uint8{
+ hashToHashId(crypto.SHA256),
+ hashToHashId(crypto.SHA512),
+ hashToHashId(crypto.SHA1),
+ hashToHashId(crypto.RIPEMD160),
+ }
+ // In the event that a recipient doesn't specify any supported ciphers
+ // or hash functions, these are the ones that we assume that every
+ // implementation supports.
+ defaultCiphers := candidateCiphers[len(candidateCiphers)-1:]
+ defaultHashes := candidateHashes[len(candidateHashes)-1:]
+
+ encryptKeys := make([]Key, len(to))
+ for i := range to {
+ encryptKeys[i] = to[i].encryptionKey()
+ if encryptKeys[i].PublicKey == nil {
+ return nil, error.InvalidArgumentError("cannot encrypt a message to key id " + strconv.Uitob64(to[i].PrimaryKey.KeyId, 16) + " because it has no encryption keys")
+ }
+
+ sig := to[i].primaryIdentity().SelfSignature
+
+ preferredSymmetric := sig.PreferredSymmetric
+ if len(preferredSymmetric) == 0 {
+ preferredSymmetric = defaultCiphers
+ }
+ preferredHashes := sig.PreferredHash
+ if len(preferredHashes) == 0 {
+ preferredHashes = defaultHashes
+ }
+ candidateCiphers = intersectPreferences(candidateCiphers, preferredSymmetric)
+ candidateHashes = intersectPreferences(candidateHashes, preferredHashes)
+ }
+
+ if len(candidateCiphers) == 0 || len(candidateHashes) == 0 {
+ return nil, error.InvalidArgumentError("cannot encrypt because recipient set shares no common algorithms")
+ }
+
+ cipher := packet.CipherFunction(candidateCiphers[0])
+ hash, _ := s2k.HashIdToHash(candidateHashes[0])
+ symKey := make([]byte, cipher.KeySize())
+ if _, err := io.ReadFull(rand.Reader, symKey); err != nil {
+ return nil, err
+ }
+
+ for _, key := range encryptKeys {
+ if err := packet.SerializeEncryptedKey(ciphertext, rand.Reader, key.PublicKey, cipher, symKey); err != nil {
+ return nil, err
+ }
+ }
+
+ encryptedData, err := packet.SerializeSymmetricallyEncrypted(ciphertext, cipher, symKey)
+ if err != nil {
+ return
+ }
+
+ if signer != nil {
+ ops := &packet.OnePassSignature{
+ SigType: packet.SigTypeBinary,
+ Hash: hash,
+ PubKeyAlgo: signer.PubKeyAlgo,
+ KeyId: signer.KeyId,
+ IsLast: true,
+ }
+ if err := ops.Serialize(encryptedData); err != nil {
+ return nil, err
+ }
+ }
+
+ if hints == nil {
+ hints = &FileHints{}
+ }
+
+ w := encryptedData
+ if signer != nil {
+ // If we need to write a signature packet after the literal
+ // data then we need to stop literalData from closing
+ // encryptedData.
+ w = noOpCloser{encryptedData}
+
+ }
+ literalData, err := packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, hints.EpochSeconds)
+ if err != nil {
+ return nil, err
+ }
+
+ if signer != nil {
+ return signatureWriter{encryptedData, literalData, hash, hash.New(), signer}, nil
+ }
+ return literalData, nil
+}
+
+// signatureWriter hashes the contents of a message while passing it along to
+// literalData. When closed, it closes literalData, writes a signature packet
+// to encryptedData and then also closes encryptedData.
+type signatureWriter struct {
+ encryptedData io.WriteCloser
+ literalData io.WriteCloser
+ hashType crypto.Hash
+ h hash.Hash
+ signer *packet.PrivateKey
+}
+
+func (s signatureWriter) Write(data []byte) (int, os.Error) {
+ s.h.Write(data)
+ return s.literalData.Write(data)
+}
+
+func (s signatureWriter) Close() os.Error {
+ sig := &packet.Signature{
+ SigType: packet.SigTypeBinary,
+ PubKeyAlgo: s.signer.PubKeyAlgo,
+ Hash: s.hashType,
+ CreationTime: uint32(time.Seconds()),
+ IssuerKeyId: &s.signer.KeyId,
+ }
+
+ if err := sig.Sign(s.h, s.signer); err != nil {
+ return err
+ }
+ if err := s.literalData.Close(); err != nil {
+ return err
+ }
+ if err := sig.Serialize(s.encryptedData); err != nil {
+ return err
+ }
+ return s.encryptedData.Close()
+}
+
+// noOpCloser is like an ioutil.NopCloser, but for an io.Writer.
+// TODO: we have two of these in OpenPGP packages alone. This probably needs
+// to be promoted somewhere more common.
+type noOpCloser struct {
+ w io.Writer
+}
+
+func (c noOpCloser) Write(data []byte) (n int, err os.Error) {
+ return c.w.Write(data)
+}
+
+func (c noOpCloser) Close() os.Error {
+ return nil
+}
diff --git a/src/pkg/crypto/openpgp/write_test.go b/src/pkg/crypto/openpgp/write_test.go
index 8551aeb63..c542dfa45 100644
--- a/src/pkg/crypto/openpgp/write_test.go
+++ b/src/pkg/crypto/openpgp/write_test.go
@@ -9,6 +9,7 @@ import (
"crypto/rand"
"os"
"io"
+ "io/ioutil"
"testing"
"time"
)
@@ -120,3 +121,113 @@ func TestSymmetricEncryption(t *testing.T) {
t.Errorf("recovered message incorrect got '%s', want '%s'", messageBuf.Bytes(), message)
}
}
+
+var testEncryptionTests = []struct {
+ keyRingHex string
+ isSigned bool
+}{
+ {
+ testKeys1And2PrivateHex,
+ false,
+ },
+ {
+ testKeys1And2PrivateHex,
+ true,
+ },
+ {
+ dsaElGamalTestKeysHex,
+ false,
+ },
+ {
+ dsaElGamalTestKeysHex,
+ true,
+ },
+}
+
+func TestEncryption(t *testing.T) {
+ for i, test := range testEncryptionTests {
+ kring, _ := ReadKeyRing(readerFromHex(test.keyRingHex))
+
+ passphrase := []byte("passphrase")
+ for _, entity := range kring {
+ if entity.PrivateKey != nil && entity.PrivateKey.Encrypted {
+ err := entity.PrivateKey.Decrypt(passphrase)
+ if err != nil {
+ t.Errorf("#%d: failed to decrypt key", i)
+ }
+ }
+ for _, subkey := range entity.Subkeys {
+ if subkey.PrivateKey != nil && subkey.PrivateKey.Encrypted {
+ err := subkey.PrivateKey.Decrypt(passphrase)
+ if err != nil {
+ t.Errorf("#%d: failed to decrypt subkey", i)
+ }
+ }
+ }
+ }
+
+ var signed *Entity
+ if test.isSigned {
+ signed = kring[0]
+ }
+
+ buf := new(bytes.Buffer)
+ w, err := Encrypt(buf, kring[:1], signed, nil /* no hints */ )
+ if err != nil {
+ t.Errorf("#%d: error in Encrypt: %s", i, err)
+ continue
+ }
+
+ const message = "testing"
+ _, err = w.Write([]byte(message))
+ if err != nil {
+ t.Errorf("#%d: error writing plaintext: %s", i, err)
+ continue
+ }
+ err = w.Close()
+ if err != nil {
+ t.Errorf("#%d: error closing WriteCloser: %s", i, err)
+ continue
+ }
+
+ md, err := ReadMessage(buf, kring, nil /* no prompt */ )
+ if err != nil {
+ t.Errorf("#%d: error reading message: %s", i, err)
+ continue
+ }
+
+ if test.isSigned {
+ expectedKeyId := kring[0].signingKey().PublicKey.KeyId
+ if md.SignedByKeyId != expectedKeyId {
+ t.Errorf("#%d: message signed by wrong key id, got: %d, want: %d", i, *md.SignedBy, expectedKeyId)
+ }
+ if md.SignedBy == nil {
+ t.Errorf("#%d: failed to find the signing Entity", i)
+ }
+ }
+
+ plaintext, err := ioutil.ReadAll(md.UnverifiedBody)
+ if err != nil {
+ t.Errorf("#%d: error reading encrypted contents: %s", i, err)
+ continue
+ }
+
+ expectedKeyId := kring[0].encryptionKey().PublicKey.KeyId
+ if len(md.EncryptedToKeyIds) != 1 || md.EncryptedToKeyIds[0] != expectedKeyId {
+ t.Errorf("#%d: expected message to be encrypted to %v, but got %#v", i, expectedKeyId, md.EncryptedToKeyIds)
+ }
+
+ if string(plaintext) != message {
+ t.Errorf("#%d: got: %s, want: %s", i, string(plaintext), message)
+ }
+
+ if test.isSigned {
+ if md.SignatureError != nil {
+ t.Errorf("#%d: signature error: %s", i, err)
+ }
+ if md.Signature == nil {
+ t.Error("signature missing")
+ }
+ }
+ }
+}
diff --git a/src/pkg/crypto/rsa/pkcs1v15.go b/src/pkg/crypto/rsa/pkcs1v15.go
index 3defa62ea..600623114 100644
--- a/src/pkg/crypto/rsa/pkcs1v15.go
+++ b/src/pkg/crypto/rsa/pkcs1v15.go
@@ -232,11 +232,11 @@ func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte)
func pkcs1v15HashInfo(hash crypto.Hash, inLen int) (hashLen int, prefix []byte, err os.Error) {
hashLen = hash.Size()
if inLen != hashLen {
- return 0, nil, os.ErrorString("input must be hashed message")
+ return 0, nil, os.NewError("input must be hashed message")
}
prefix, ok := hashPrefixes[hash]
if !ok {
- return 0, nil, os.ErrorString("unsupported hash function")
+ return 0, nil, os.NewError("unsupported hash function")
}
return
}
diff --git a/src/pkg/crypto/rsa/rsa.go b/src/pkg/crypto/rsa/rsa.go
index 380f71570..6957659f2 100644
--- a/src/pkg/crypto/rsa/rsa.go
+++ b/src/pkg/crypto/rsa/rsa.go
@@ -64,7 +64,7 @@ func (priv *PrivateKey) Validate() os.Error {
// easy for an attack to generate composites that pass this test.
for _, prime := range priv.Primes {
if !big.ProbablyPrime(prime, 20) {
- return os.ErrorString("prime factor is composite")
+ return os.NewError("prime factor is composite")
}
}
@@ -74,7 +74,7 @@ func (priv *PrivateKey) Validate() os.Error {
modulus.Mul(modulus, prime)
}
if modulus.Cmp(priv.N) != 0 {
- return os.ErrorString("invalid modulus")
+ return os.NewError("invalid modulus")
}
// Check that e and totient(Πprimes) are coprime.
totient := new(big.Int).Set(bigOne)
@@ -88,13 +88,13 @@ func (priv *PrivateKey) Validate() os.Error {
y := new(big.Int)
big.GcdInt(gcd, x, y, totient, e)
if gcd.Cmp(bigOne) != 0 {
- return os.ErrorString("invalid public exponent E")
+ return os.NewError("invalid public exponent E")
}
// Check that de ≡ 1 (mod totient(Πprimes))
de := new(big.Int).Mul(priv.D, e)
de.Mod(de, totient)
if de.Cmp(bigOne) != 0 {
- return os.ErrorString("invalid private exponent D")
+ return os.NewError("invalid private exponent D")
}
return nil
}
@@ -127,7 +127,7 @@ func GenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (priv *Priva
priv.E = 3
if nprimes < 2 {
- return nil, os.ErrorString("rsa.GenerateMultiPrimeKey: nprimes must be >= 2")
+ return nil, os.NewError("rsa.GenerateMultiPrimeKey: nprimes must be >= 2")
}
primes := make([]*big.Int, nprimes)
diff --git a/src/pkg/crypto/tls/conn.go b/src/pkg/crypto/tls/conn.go
index 097e182bd..fac65afd9 100644
--- a/src/pkg/crypto/tls/conn.go
+++ b/src/pkg/crypto/tls/conn.go
@@ -790,10 +790,10 @@ func (c *Conn) VerifyHostname(host string) os.Error {
c.handshakeMutex.Lock()
defer c.handshakeMutex.Unlock()
if !c.isClient {
- return os.ErrorString("VerifyHostname called on TLS server connection")
+ return os.NewError("VerifyHostname called on TLS server connection")
}
if !c.handshakeComplete {
- return os.ErrorString("TLS handshake has not yet been performed")
+ return os.NewError("TLS handshake has not yet been performed")
}
return c.peerCertificates[0].VerifyHostname(host)
}
diff --git a/src/pkg/crypto/tls/handshake_client.go b/src/pkg/crypto/tls/handshake_client.go
index c758c96d4..15604cea7 100644
--- a/src/pkg/crypto/tls/handshake_client.go
+++ b/src/pkg/crypto/tls/handshake_client.go
@@ -40,7 +40,7 @@ func (c *Conn) clientHandshake() os.Error {
_, err := io.ReadFull(c.config.rand(), hello.random[4:])
if err != nil {
c.sendAlert(alertInternalError)
- return os.ErrorString("short read from Rand")
+ return os.NewError("short read from Rand")
}
finishedHash.Write(hello.marshal())
@@ -69,7 +69,7 @@ func (c *Conn) clientHandshake() os.Error {
if !hello.nextProtoNeg && serverHello.nextProtoNeg {
c.sendAlert(alertHandshakeFailure)
- return os.ErrorString("server advertised unrequested NPN")
+ return os.NewError("server advertised unrequested NPN")
}
suite, suiteId := mutualCipherSuite(c.config.cipherSuites(), serverHello.cipherSuite)
@@ -92,7 +92,7 @@ func (c *Conn) clientHandshake() os.Error {
cert, err := x509.ParseCertificate(asn1Data)
if err != nil {
c.sendAlert(alertBadCertificate)
- return os.ErrorString("failed to parse certificate from server: " + err.String())
+ return os.NewError("failed to parse certificate from server: " + err.String())
}
certs[i] = cert
}
diff --git a/src/pkg/crypto/tls/handshake_server.go b/src/pkg/crypto/tls/handshake_server.go
index e9431c6fa..44a324041 100644
--- a/src/pkg/crypto/tls/handshake_server.go
+++ b/src/pkg/crypto/tls/handshake_server.go
@@ -173,7 +173,7 @@ FindCipherSuite:
cert, err := x509.ParseCertificate(asn1Data)
if err != nil {
c.sendAlert(alertBadCertificate)
- return os.ErrorString("could not parse client's certificate: " + err.String())
+ return os.NewError("could not parse client's certificate: " + err.String())
}
certs[i] = cert
}
@@ -182,7 +182,7 @@ FindCipherSuite:
for i := 1; i < len(certs); i++ {
if err := certs[i-1].CheckSignatureFrom(certs[i]); err != nil {
c.sendAlert(alertBadCertificate)
- return os.ErrorString("could not validate certificate signature: " + err.String())
+ return os.NewError("could not validate certificate signature: " + err.String())
}
}
@@ -229,7 +229,7 @@ FindCipherSuite:
err = rsa.VerifyPKCS1v15(pub, crypto.MD5SHA1, digest, certVerify.signature)
if err != nil {
c.sendAlert(alertBadCertificate)
- return os.ErrorString("could not validate signature of connection nonces: " + err.String())
+ return os.NewError("could not validate signature of connection nonces: " + err.String())
}
finishedHash.Write(certVerify.marshal())
diff --git a/src/pkg/crypto/tls/key_agreement.go b/src/pkg/crypto/tls/key_agreement.go
index 84f90c45a..48472fb6a 100644
--- a/src/pkg/crypto/tls/key_agreement.go
+++ b/src/pkg/crypto/tls/key_agreement.go
@@ -32,11 +32,11 @@ func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKe
}
if len(ckx.ciphertext) < 2 {
- return nil, os.ErrorString("bad ClientKeyExchange")
+ return nil, os.NewError("bad ClientKeyExchange")
}
ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1])
if ciphertextLen != len(ckx.ciphertext)-2 {
- return nil, os.ErrorString("bad ClientKeyExchange")
+ return nil, os.NewError("bad ClientKeyExchange")
}
ciphertext := ckx.ciphertext[2:]
@@ -54,7 +54,7 @@ func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKe
}
func (ka rsaKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) os.Error {
- return os.ErrorString("unexpected ServerKeyExchange")
+ return os.NewError("unexpected ServerKeyExchange")
}
func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, os.Error) {
@@ -146,7 +146,7 @@ Curve:
md5sha1 := md5SHA1Hash(clientHello.random, hello.random, serverECDHParams)
sig, err := rsa.SignPKCS1v15(config.rand(), config.Certificates[0].PrivateKey, crypto.MD5SHA1, md5sha1)
if err != nil {
- return nil, os.ErrorString("failed to sign ECDHE parameters: " + err.String())
+ return nil, os.NewError("failed to sign ECDHE parameters: " + err.String())
}
skx := new(serverKeyExchangeMsg)
@@ -162,11 +162,11 @@ Curve:
func (ka *ecdheRSAKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKeyExchangeMsg) ([]byte, os.Error) {
if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 {
- return nil, os.ErrorString("bad ClientKeyExchange")
+ return nil, os.NewError("bad ClientKeyExchange")
}
x, y := ka.curve.Unmarshal(ckx.ciphertext[1:])
if x == nil {
- return nil, os.ErrorString("bad ClientKeyExchange")
+ return nil, os.NewError("bad ClientKeyExchange")
}
x, _ = ka.curve.ScalarMult(x, y, ka.privateKey)
preMasterSecret := make([]byte, (ka.curve.BitSize+7)>>3)
@@ -176,12 +176,14 @@ func (ka *ecdheRSAKeyAgreement) processClientKeyExchange(config *Config, ckx *cl
return preMasterSecret, nil
}
+var errServerKeyExchange = os.NewError("invalid ServerKeyExchange")
+
func (ka *ecdheRSAKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) os.Error {
if len(skx.key) < 4 {
- goto Error
+ return errServerKeyExchange
}
if skx.key[0] != 3 { // named curve
- return os.ErrorString("server selected unsupported curve")
+ return os.NewError("server selected unsupported curve")
}
curveid := uint16(skx.key[1])<<8 | uint16(skx.key[2])
@@ -193,39 +195,36 @@ func (ka *ecdheRSAKeyAgreement) processServerKeyExchange(config *Config, clientH
case curveP521:
ka.curve = elliptic.P521()
default:
- return os.ErrorString("server selected unsupported curve")
+ return os.NewError("server selected unsupported curve")
}
publicLen := int(skx.key[3])
if publicLen+4 > len(skx.key) {
- goto Error
+ return errServerKeyExchange
}
ka.x, ka.y = ka.curve.Unmarshal(skx.key[4 : 4+publicLen])
if ka.x == nil {
- goto Error
+ return errServerKeyExchange
}
serverECDHParams := skx.key[:4+publicLen]
sig := skx.key[4+publicLen:]
if len(sig) < 2 {
- goto Error
+ return errServerKeyExchange
}
sigLen := int(sig[0])<<8 | int(sig[1])
if sigLen+2 != len(sig) {
- goto Error
+ return errServerKeyExchange
}
sig = sig[2:]
md5sha1 := md5SHA1Hash(clientHello.random, serverHello.random, serverECDHParams)
return rsa.VerifyPKCS1v15(cert.PublicKey.(*rsa.PublicKey), crypto.MD5SHA1, md5sha1, sig)
-
-Error:
- return os.ErrorString("invalid ServerKeyExchange")
}
func (ka *ecdheRSAKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, os.Error) {
if ka.curve == nil {
- return nil, nil, os.ErrorString("missing ServerKeyExchange message")
+ return nil, nil, os.NewError("missing ServerKeyExchange message")
}
priv, mx, my, err := ka.curve.GenerateKey(config.rand())
if err != nil {
diff --git a/src/pkg/crypto/tls/tls.go b/src/pkg/crypto/tls/tls.go
index 9e5c9270a..4f0859fee 100644
--- a/src/pkg/crypto/tls/tls.go
+++ b/src/pkg/crypto/tls/tls.go
@@ -147,19 +147,19 @@ func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert Certificate, err os.Err
}
if len(cert.Certificate) == 0 {
- err = os.ErrorString("crypto/tls: failed to parse certificate PEM data")
+ err = os.NewError("crypto/tls: failed to parse certificate PEM data")
return
}
keyDERBlock, _ := pem.Decode(keyPEMBlock)
if keyDERBlock == nil {
- err = os.ErrorString("crypto/tls: failed to parse key PEM data")
+ err = os.NewError("crypto/tls: failed to parse key PEM data")
return
}
key, err := x509.ParsePKCS1PrivateKey(keyDERBlock.Bytes)
if err != nil {
- err = os.ErrorString("crypto/tls: failed to parse key: " + err.String())
+ err = os.NewError("crypto/tls: failed to parse key: " + err.String())
return
}
@@ -173,7 +173,7 @@ func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert Certificate, err os.Err
}
if x509Cert.PublicKeyAlgorithm != x509.RSA || x509Cert.PublicKey.(*rsa.PublicKey).N.Cmp(key.PublicKey.N) != 0 {
- err = os.ErrorString("crypto/tls: private key does not match public key")
+ err = os.NewError("crypto/tls: private key does not match public key")
return
}
diff --git a/src/pkg/crypto/x509/verify_test.go b/src/pkg/crypto/x509/verify_test.go
index 6a103dcfb..7a631186a 100644
--- a/src/pkg/crypto/x509/verify_test.go
+++ b/src/pkg/crypto/x509/verify_test.go
@@ -120,7 +120,7 @@ func expectAuthorityUnknown(t *testing.T, i int, err os.Error) (ok bool) {
func certificateFromPEM(pemBytes string) (*Certificate, os.Error) {
block, _ := pem.Decode([]byte(pemBytes))
if block == nil {
- return nil, os.ErrorString("failed to decode PEM")
+ return nil, os.NewError("failed to decode PEM")
}
return ParseCertificate(block.Bytes)
}
diff --git a/src/pkg/crypto/x509/x509.go b/src/pkg/crypto/x509/x509.go
index b10ffb0a2..8bafeda5c 100644
--- a/src/pkg/crypto/x509/x509.go
+++ b/src/pkg/crypto/x509/x509.go
@@ -58,11 +58,11 @@ func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err os.Error) {
}
if priv.Version > 1 {
- return nil, os.ErrorString("x509: unsupported private key version")
+ return nil, os.NewError("x509: unsupported private key version")
}
if priv.N.Sign() <= 0 || priv.D.Sign() <= 0 || priv.P.Sign() <= 0 || priv.Q.Sign() <= 0 {
- return nil, os.ErrorString("private key contains zero or negative value")
+ return nil, os.NewError("private key contains zero or negative value")
}
key = new(rsa.PrivateKey)
@@ -77,7 +77,7 @@ func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err os.Error) {
key.Primes[1] = priv.Q
for i, a := range priv.AdditionalPrimes {
if a.Prime.Sign() <= 0 {
- return nil, os.ErrorString("private key contains zero or negative prime")
+ return nil, os.NewError("private key contains zero or negative prime")
}
key.Primes[i+2] = a.Prime
// We ignore the other two values because rsa will calculate
@@ -457,10 +457,10 @@ func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature
return err
}
if dsaSig.R.Sign() <= 0 || dsaSig.S.Sign() <= 0 {
- return os.ErrorString("DSA signature contained zero or negative values")
+ return os.NewError("DSA signature contained zero or negative values")
}
if !dsa.Verify(pub, digest, dsaSig.R, dsaSig.S) {
- return os.ErrorString("DSA verification failure")
+ return os.NewError("DSA verification failure")
}
return
}
@@ -535,7 +535,7 @@ func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{
return nil, err
}
if p.Sign() <= 0 || params.P.Sign() <= 0 || params.Q.Sign() <= 0 || params.G.Sign() <= 0 {
- return nil, os.ErrorString("zero or negative DSA parameter")
+ return nil, os.NewError("zero or negative DSA parameter")
}
pub := &dsa.PublicKey{
Parameters: dsa.Parameters{
@@ -571,7 +571,7 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) {
}
if in.TBSCertificate.SerialNumber.Sign() < 0 {
- return nil, os.ErrorString("negative serial number")
+ return nil, os.NewError("negative serial number")
}
out.Version = in.TBSCertificate.Version + 1
diff --git a/src/pkg/debug/dwarf/type.go b/src/pkg/debug/dwarf/type.go
index f9acf119f..f35365ebe 100644
--- a/src/pkg/debug/dwarf/type.go
+++ b/src/pkg/debug/dwarf/type.go
@@ -352,8 +352,8 @@ func (d *Data) Type(off Offset) (Type, os.Error) {
}
}
if ndim == 0 {
- err = DecodeError{"info", e.Offset, "missing dimension for array"}
- goto Error
+ // LLVM generates this for x[].
+ t.Count = -1
}
case TagBaseType:
@@ -566,12 +566,13 @@ func (d *Data) Type(off Offset) (Type, os.Error) {
goto Error
}
- b, ok := e.Val(AttrByteSize).(int64)
- if !ok {
- b = -1
+ {
+ b, ok := e.Val(AttrByteSize).(int64)
+ if !ok {
+ b = -1
+ }
+ typ.Common().ByteSize = b
}
- typ.Common().ByteSize = b
-
return typ, nil
Error:
diff --git a/src/pkg/debug/elf/file.go b/src/pkg/debug/elf/file.go
index 9ae8b413d..346fe2a78 100644
--- a/src/pkg/debug/elf/file.go
+++ b/src/pkg/debug/elf/file.go
@@ -81,7 +81,7 @@ func (s *Section) Data() ([]byte, os.Error) {
// specified link value.
func (f *File) stringTable(link uint32) ([]byte, os.Error) {
if link <= 0 || link >= uint32(len(f.Sections)) {
- return nil, os.ErrorString("section has invalid string table link")
+ return nil, os.NewError("section has invalid string table link")
}
return f.Sections[link].Data()
}
@@ -341,27 +341,27 @@ func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, os.Error) {
return f.getSymbols32(typ)
}
- return nil, nil, os.ErrorString("not implemented")
+ return nil, nil, os.NewError("not implemented")
}
func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, os.Error) {
symtabSection := f.SectionByType(typ)
if symtabSection == nil {
- return nil, nil, os.ErrorString("no symbol section")
+ return nil, nil, os.NewError("no symbol section")
}
data, err := symtabSection.Data()
if err != nil {
- return nil, nil, os.ErrorString("cannot load symbol section")
+ return nil, nil, os.NewError("cannot load symbol section")
}
symtab := bytes.NewBuffer(data)
if symtab.Len()%Sym32Size != 0 {
- return nil, nil, os.ErrorString("length of symbol section is not a multiple of SymSize")
+ return nil, nil, os.NewError("length of symbol section is not a multiple of SymSize")
}
strdata, err := f.stringTable(symtabSection.Link)
if err != nil {
- return nil, nil, os.ErrorString("cannot load string table section")
+ return nil, nil, os.NewError("cannot load string table section")
}
// The first entry is all zeros.
@@ -390,21 +390,21 @@ func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, os.Error) {
func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, os.Error) {
symtabSection := f.SectionByType(typ)
if symtabSection == nil {
- return nil, nil, os.ErrorString("no symbol section")
+ return nil, nil, os.NewError("no symbol section")
}
data, err := symtabSection.Data()
if err != nil {
- return nil, nil, os.ErrorString("cannot load symbol section")
+ return nil, nil, os.NewError("cannot load symbol section")
}
symtab := bytes.NewBuffer(data)
if symtab.Len()%Sym64Size != 0 {
- return nil, nil, os.ErrorString("length of symbol section is not a multiple of Sym64Size")
+ return nil, nil, os.NewError("length of symbol section is not a multiple of Sym64Size")
}
strdata, err := f.stringTable(symtabSection.Link)
if err != nil {
- return nil, nil, os.ErrorString("cannot load string table section")
+ return nil, nil, os.NewError("cannot load string table section")
}
// The first entry is all zeros.
@@ -462,12 +462,12 @@ func (f *File) applyRelocations(dst []byte, rels []byte) os.Error {
return f.applyRelocationsAMD64(dst, rels)
}
- return os.ErrorString("not implemented")
+ return os.NewError("not implemented")
}
func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) os.Error {
if len(rels)%Sym64Size != 0 {
- return os.ErrorString("length of relocation section is not a multiple of Sym64Size")
+ return os.NewError("length of relocation section is not a multiple of Sym64Size")
}
symbols, _, err := f.getSymbols(SHT_SYMTAB)
@@ -546,6 +546,12 @@ func (f *File) DWARF() (*dwarf.Data, os.Error) {
return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
}
+// Symbols returns the symbol table for f.
+func (f *File) Symbols() ([]Symbol, os.Error) {
+ sym, _, err := f.getSymbols(SHT_SYMTAB)
+ return sym, err
+}
+
type ImportedSymbol struct {
Name string
Version string
diff --git a/src/pkg/debug/elf/file_test.go b/src/pkg/debug/elf/file_test.go
index 84068ea12..37f62796e 100644
--- a/src/pkg/debug/elf/file_test.go
+++ b/src/pkg/debug/elf/file_test.go
@@ -136,15 +136,15 @@ type relocationTest struct {
var relocationTests = []relocationTest{
{
- "testdata/go-relocation-test-gcc441-x86-64.o",
+ "testdata/go-relocation-test-gcc441-x86-64.obj",
&dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}},
},
{
- "testdata/go-relocation-test-gcc441-x86.o",
+ "testdata/go-relocation-test-gcc441-x86.obj",
&dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "t.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x5)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}},
},
{
- "testdata/go-relocation-test-gcc424-x86-64.o",
+ "testdata/go-relocation-test-gcc424-x86-64.obj",
&dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.2.4 (Ubuntu 4.2.4-1ubuntu4)"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc424.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}},
},
}
diff --git a/src/pkg/debug/elf/testdata/go-relocation-test-gcc424-x86-64.o b/src/pkg/debug/elf/testdata/go-relocation-test-gcc424-x86-64.obj
index a7c6d6e56..a7c6d6e56 100644
--- a/src/pkg/debug/elf/testdata/go-relocation-test-gcc424-x86-64.o
+++ b/src/pkg/debug/elf/testdata/go-relocation-test-gcc424-x86-64.obj
Binary files differ
diff --git a/src/pkg/debug/elf/testdata/go-relocation-test-gcc441-x86-64.o b/src/pkg/debug/elf/testdata/go-relocation-test-gcc441-x86-64.obj
index 2d37ab6e6..2d37ab6e6 100644
--- a/src/pkg/debug/elf/testdata/go-relocation-test-gcc441-x86-64.o
+++ b/src/pkg/debug/elf/testdata/go-relocation-test-gcc441-x86-64.obj
Binary files differ
diff --git a/src/pkg/debug/elf/testdata/go-relocation-test-gcc441-x86.o b/src/pkg/debug/elf/testdata/go-relocation-test-gcc441-x86.obj
index 0d59fe303..0d59fe303 100644
--- a/src/pkg/debug/elf/testdata/go-relocation-test-gcc441-x86.o
+++ b/src/pkg/debug/elf/testdata/go-relocation-test-gcc441-x86.obj
Binary files differ
diff --git a/src/pkg/debug/proc/proc_linux.go b/src/pkg/debug/proc/proc_linux.go
index 153c3e99b..5831b0e97 100644
--- a/src/pkg/debug/proc/proc_linux.go
+++ b/src/pkg/debug/proc/proc_linux.go
@@ -1284,9 +1284,11 @@ func Attach(pid int) (Process, os.Error) {
// details.
func StartProcess(argv0 string, argv []string, attr *os.ProcAttr) (Process, os.Error) {
sysattr := &syscall.ProcAttr{
- Dir: attr.Dir,
- Env: attr.Env,
- Ptrace: true,
+ Dir: attr.Dir,
+ Env: attr.Env,
+ Sys: &syscall.SysProcAttr{
+ Ptrace: true,
+ },
}
p := newProcess(-1)
diff --git a/src/pkg/deps.bash b/src/pkg/deps.bash
index a8e3dfc3a..2095ec1d8 100755
--- a/src/pkg/deps.bash
+++ b/src/pkg/deps.bash
@@ -15,7 +15,13 @@ fi
# Get list of directories from Makefile
dirs=$(gomake --no-print-directory echo-dirs)
-dirpat=$(echo $dirs C | sed 's/ /|/g; s/.*/^(&)$/')
+dirpat=$(echo $dirs C | awk '{
+ for(i=1;i<=NF;i++){
+ x=$i
+ gsub("/", "\\/", x)
+ printf("/^(%s)$/\n", x)
+ }
+}')
for dir in $dirs; do (
cd $dir || exit 1
@@ -30,7 +36,7 @@ for dir in $dirs; do (
deps=$(
sed -n '/^import.*"/p; /^import[ \t]*(/,/^)/p' $sources /dev/null |
cut -d '"' -f2 |
- egrep "$dirpat" |
+ awk "$dirpat" |
grep -v "^$dir\$" |
sed 's/$/.install/' |
sed 's;^C\.install;runtime/cgo.install;' |
diff --git a/src/pkg/encoding/pem/pem.go b/src/pkg/encoding/pem/pem.go
index c2398807f..ebe57edc0 100644
--- a/src/pkg/encoding/pem/pem.go
+++ b/src/pkg/encoding/pem/pem.go
@@ -86,7 +86,7 @@ func Decode(data []byte) (p *Block, rest []byte) {
typeLine, rest := getLine(rest)
if !bytes.HasSuffix(typeLine, pemEndOfLine) {
- goto Error
+ return decodeError(data, rest)
}
typeLine = typeLine[0 : len(typeLine)-len(pemEndOfLine)]
@@ -118,22 +118,23 @@ func Decode(data []byte) (p *Block, rest []byte) {
i := bytes.Index(rest, pemEnd)
if i < 0 {
- goto Error
+ return decodeError(data, rest)
}
base64Data := removeWhitespace(rest[0:i])
p.Bytes = make([]byte, base64.StdEncoding.DecodedLen(len(base64Data)))
n, err := base64.StdEncoding.Decode(p.Bytes, base64Data)
if err != nil {
- goto Error
+ return decodeError(data, rest)
}
p.Bytes = p.Bytes[0:n]
_, rest = getLine(rest[i+len(pemEnd):])
return
+}
-Error:
+func decodeError(data, rest []byte) (*Block, []byte) {
// If we get here then we have rejected a likely looking, but
// ultimately invalid PEM block. We need to start over from a new
// position. We have consumed the preamble line and will have consumed
@@ -154,11 +155,11 @@ Error:
//
// we've failed to parse using the first BEGIN line
// and now will try again, using the second BEGIN line.
- p, rest = Decode(rest)
+ p, rest := Decode(rest)
if p == nil {
rest = data
}
- return
+ return p, rest
}
const pemLineLength = 64
diff --git a/src/pkg/exec/Makefile b/src/pkg/exec/Makefile
index 262ecac85..90bb74b41 100644
--- a/src/pkg/exec/Makefile
+++ b/src/pkg/exec/Makefile
@@ -20,6 +20,9 @@ GOFILES_linux=\
GOFILES_windows=\
lp_windows.go\
+GOFILES_plan9=\
+ lp_plan9.go\
+
GOFILES+=$(GOFILES_$(GOOS))
include ../../Make.pkg
diff --git a/src/pkg/exec/exec.go b/src/pkg/exec/exec.go
index 935f24c21..5b988d5eb 100644
--- a/src/pkg/exec/exec.go
+++ b/src/pkg/exec/exec.go
@@ -12,6 +12,7 @@ import (
"io"
"os"
"strconv"
+ "syscall"
)
// Error records the name of a binary that failed to be be executed
@@ -62,6 +63,10 @@ type Cmd struct {
Stdout io.Writer
Stderr io.Writer
+ // SysProcAttr holds optional, operating system-specific attributes.
+ // Run passes it to os.StartProcess as the os.ProcAttr's Sys field.
+ SysProcAttr *syscall.SysProcAttr
+
// Process is the underlying process, once started.
Process *os.Process
@@ -225,6 +230,7 @@ func (c *Cmd) Start() os.Error {
Dir: c.Dir,
Files: c.childFiles,
Env: c.envv(),
+ Sys: c.SysProcAttr,
})
if err != nil {
return err
diff --git a/src/pkg/exec/lp_plan9.go b/src/pkg/exec/lp_plan9.go
new file mode 100644
index 000000000..c4e2a7a0f
--- /dev/null
+++ b/src/pkg/exec/lp_plan9.go
@@ -0,0 +1,51 @@
+// 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 exec
+
+import (
+ "os"
+ "strings"
+)
+
+// ErrNotFound is the error resulting if a path search failed to find an executable file.
+var ErrNotFound = os.NewError("executable file not found in $path")
+
+func findExecutable(file string) os.Error {
+ d, err := os.Stat(file)
+ if err != nil {
+ return err
+ }
+ if d.IsRegular() && d.Permission()&0111 != 0 {
+ return nil
+ }
+ return os.EPERM
+}
+
+// LookPath searches for an executable binary named file
+// in the directories named by the path environment variable.
+// If file begins with "/", "#", "./", or "../", it is tried
+// directly and the path is not consulted.
+func LookPath(file string) (string, os.Error) {
+ // skip the path lookup for these prefixes
+ skip := []string{"/", "#", "./", "../"}
+
+ for _, p := range skip {
+ if strings.HasPrefix(file, p) {
+ err := findExecutable(file)
+ if err == nil {
+ return file, nil
+ }
+ return "", &Error{file, err}
+ }
+ }
+
+ path := os.Getenv("path")
+ for _, dir := range strings.Split(path, "\000", -1) {
+ if err := findExecutable(dir + "/" + file); err == nil {
+ return dir + "/" + file, nil
+ }
+ }
+ return "", &Error{file, ErrNotFound}
+}
diff --git a/src/pkg/exec/lp_unix.go b/src/pkg/exec/lp_unix.go
index 3fc3be832..cdf720768 100644
--- a/src/pkg/exec/lp_unix.go
+++ b/src/pkg/exec/lp_unix.go
@@ -10,7 +10,7 @@ import (
)
// ErrNotFound is the error resulting if a path search failed to find an executable file.
-var ErrNotFound = os.ErrorString("executable file not found in $PATH")
+var ErrNotFound = os.NewError("executable file not found in $PATH")
func findExecutable(file string) os.Error {
d, err := os.Stat(file)
diff --git a/src/pkg/exec/lp_windows.go b/src/pkg/exec/lp_windows.go
index 758861021..47763458f 100644
--- a/src/pkg/exec/lp_windows.go
+++ b/src/pkg/exec/lp_windows.go
@@ -10,7 +10,7 @@ import (
)
// ErrNotFound is the error resulting if a path search failed to find an executable file.
-var ErrNotFound = os.ErrorString("executable file not found in %PATH%")
+var ErrNotFound = os.NewError("executable file not found in %PATH%")
func chkStat(file string) os.Error {
d, err := os.Stat(file)
@@ -38,20 +38,25 @@ func findExecutable(file string, exts []string) (string, os.Error) {
return f, nil
}
}
- return ``, ErrNotFound
+ return ``, os.ENOENT
}
func LookPath(file string) (f string, err os.Error) {
+ x := os.Getenv(`PATHEXT`)
+ if x == `` {
+ x = `.COM;.EXE;.BAT;.CMD`
+ }
exts := []string{}
- if x := os.Getenv(`PATHEXT`); x != `` {
- exts = strings.Split(strings.ToLower(x), `;`, -1)
- for i, e := range exts {
- if e == `` || e[0] != '.' {
- exts[i] = `.` + e
- }
+ for _, e := range strings.Split(strings.ToLower(x), `;`, -1) {
+ if e == "" {
+ continue
+ }
+ if e[0] != '.' {
+ e = "." + e
}
+ exts = append(exts, e)
}
- if strings.Contains(file, `\`) || strings.Contains(file, `/`) {
+ if strings.IndexAny(file, `:\/`) != -1 {
if f, err = findExecutable(file, exts); err == nil {
return
}
diff --git a/src/pkg/exp/regexp/syntax/Makefile b/src/pkg/exp/regexp/syntax/Makefile
new file mode 100644
index 000000000..8e0b4c1e6
--- /dev/null
+++ b/src/pkg/exp/regexp/syntax/Makefile
@@ -0,0 +1,13 @@
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../../Make.inc
+
+TARG=exp/regexp/syntax
+GOFILES=\
+ parse.go\
+ perl_groups.go\
+ regexp.go\
+
+include ../../../../Make.pkg
diff --git a/src/pkg/exp/regexp/syntax/make_perl_groups.pl b/src/pkg/exp/regexp/syntax/make_perl_groups.pl
new file mode 100755
index 000000000..6d1b84b10
--- /dev/null
+++ b/src/pkg/exp/regexp/syntax/make_perl_groups.pl
@@ -0,0 +1,103 @@
+#!/usr/bin/perl
+# Copyright 2008 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.
+
+# Modified version of RE2's make_perl_groups.pl.
+
+# Generate table entries giving character ranges
+# for POSIX/Perl character classes. Rather than
+# figure out what the definition is, it is easier to ask
+# Perl about each letter from 0-128 and write down
+# its answer.
+
+@posixclasses = (
+ "[:alnum:]",
+ "[:alpha:]",
+ "[:ascii:]",
+ "[:blank:]",
+ "[:cntrl:]",
+ "[:digit:]",
+ "[:graph:]",
+ "[:lower:]",
+ "[:print:]",
+ "[:punct:]",
+ "[:space:]",
+ "[:upper:]",
+ "[:word:]",
+ "[:xdigit:]",
+);
+
+@perlclasses = (
+ "\\d",
+ "\\s",
+ "\\w",
+);
+
+sub ComputeClass($) {
+ my @ranges;
+ my ($class) = @_;
+ my $regexp = "[$class]";
+ my $start = -1;
+ for (my $i=0; $i<=129; $i++) {
+ if ($i == 129) { $i = 256; }
+ if ($i <= 128 && chr($i) =~ $regexp) {
+ if ($start < 0) {
+ $start = $i;
+ }
+ } else {
+ if ($start >= 0) {
+ push @ranges, [$start, $i-1];
+ }
+ $start = -1;
+ }
+ }
+ return @ranges;
+}
+
+sub PrintClass($$@) {
+ my ($cname, $name, @ranges) = @_;
+ print "var code$cname = []int{ /* $name */\n";
+ for (my $i=0; $i<@ranges; $i++) {
+ my @a = @{$ranges[$i]};
+ printf "\t0x%x, 0x%x,\n", $a[0], $a[1];
+ }
+ print "}\n\n";
+ my $n = @ranges;
+ $negname = $name;
+ if ($negname =~ /:/) {
+ $negname =~ s/:/:^/;
+ } else {
+ $negname =~ y/a-z/A-Z/;
+ }
+ return "\t`$name`: {+1, code$cname},\n" .
+ "\t`$negname`: {-1, code$cname},\n";
+}
+
+my $gen = 0;
+
+sub PrintClasses($@) {
+ my ($cname, @classes) = @_;
+ my @entries;
+ foreach my $cl (@classes) {
+ my @ranges = ComputeClass($cl);
+ push @entries, PrintClass(++$gen, $cl, @ranges);
+ }
+ print "var ${cname}Group = map[string]charGroup{\n";
+ foreach my $e (@entries) {
+ print $e;
+ }
+ print "}\n";
+ my $count = @entries;
+}
+
+print <<EOF;
+// GENERATED BY make_perl_groups.pl; DO NOT EDIT.
+// make_perl_groups.pl >perl_groups.go
+
+package syntax
+
+EOF
+
+PrintClasses("perl", @perlclasses);
+PrintClasses("posix", @posixclasses);
diff --git a/src/pkg/exp/regexp/syntax/parse.go b/src/pkg/exp/regexp/syntax/parse.go
new file mode 100644
index 000000000..d04f25097
--- /dev/null
+++ b/src/pkg/exp/regexp/syntax/parse.go
@@ -0,0 +1,1220 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syntax
+
+import (
+ "os"
+ "sort"
+ "strings"
+ "unicode"
+ "utf8"
+)
+
+// An Error describes a failure to parse a regular expression
+// and gives the offending expression.
+type Error struct {
+ Code ErrorCode
+ Expr string
+}
+
+func (e *Error) String() string {
+ return "error parsing regexp: " + e.Code.String() + ": `" + e.Expr + "`"
+}
+
+// An ErrorCode describes a failure to parse a regular expression.
+type ErrorCode string
+
+const (
+ // Unexpected error
+ ErrInternalError ErrorCode = "regexp/syntax: internal error"
+
+ // Parse errors
+ ErrInvalidCharClass ErrorCode = "invalid character class"
+ ErrInvalidCharRange ErrorCode = "invalid character class range"
+ ErrInvalidEscape ErrorCode = "invalid escape sequence"
+ ErrInvalidNamedCapture ErrorCode = "invalid named capture"
+ ErrInvalidPerlOp ErrorCode = "invalid or unsupported Perl syntax"
+ ErrInvalidRepeatOp ErrorCode = "invalid nested repetition operator"
+ ErrInvalidRepeatSize ErrorCode = "invalid repeat count"
+ ErrInvalidUTF8 ErrorCode = "invalid UTF-8"
+ ErrMissingBracket ErrorCode = "missing closing ]"
+ ErrMissingParen ErrorCode = "missing closing )"
+ ErrMissingRepeatArgument ErrorCode = "missing argument to repetition operator"
+ ErrTrailingBackslash ErrorCode = "trailing backslash at end of expression"
+)
+
+func (e ErrorCode) String() string {
+ return string(e)
+}
+
+// Flags control the behavior of the parser and record information about regexp context.
+type Flags uint16
+
+const (
+ FoldCase Flags = 1 << iota // case-insensitive match
+ Literal // treat pattern as literal string
+ ClassNL // allow character classes like [^a-z] and [[:space:]] to match newline
+ DotNL // allow . to match newline
+ OneLine // treat ^ and $ as only matching at beginning and end of text
+ NonGreedy // make repetition operators default to non-greedy
+ PerlX // allow Perl extensions
+ UnicodeGroups // allow \p{Han}, \P{Han} for Unicode group and negation
+ WasDollar // regexp OpEndText was $, not \z
+ Simple // regexp contains no counted repetition
+
+ MatchNL = ClassNL | DotNL
+
+ Perl = ClassNL | OneLine | PerlX | UnicodeGroups // as close to Perl as possible
+ POSIX Flags = 0 // POSIX syntax
+)
+
+// Pseudo-ops for parsing stack.
+const (
+ opLeftParen = opPseudo + iota
+ opVerticalBar
+)
+
+type parser struct {
+ flags Flags // parse mode flags
+ stack []*Regexp // stack of parsed expressions
+ numCap int // number of capturing groups seen
+ wholeRegexp string
+}
+
+// Parse stack manipulation.
+
+// push pushes the regexp re onto the parse stack and returns the regexp.
+func (p *parser) push(re *Regexp) *Regexp {
+ // TODO: automatic concatenation
+ // TODO: turn character class into literal
+ // TODO: compute simple
+
+ p.stack = append(p.stack, re)
+ return re
+}
+
+// newLiteral returns a new OpLiteral Regexp with the given flags
+func newLiteral(r int, flags Flags) *Regexp {
+ re := &Regexp{
+ Op: OpLiteral,
+ Flags: flags,
+ }
+ re.Rune0[0] = r
+ re.Rune = re.Rune0[:1]
+ return re
+}
+
+// literal pushes a literal regexp for the rune r on the stack
+// and returns that regexp.
+func (p *parser) literal(r int) *Regexp {
+ return p.push(newLiteral(r, p.flags))
+}
+
+// op pushes a regexp with the given op onto the stack
+// and returns that regexp.
+func (p *parser) op(op Op) *Regexp {
+ return p.push(&Regexp{Op: op, Flags: p.flags})
+}
+
+// repeat replaces the top stack element with itself repeated
+// according to op.
+func (p *parser) repeat(op Op, min, max int, opstr, t, lastRepeat string) (string, os.Error) {
+ flags := p.flags
+ if p.flags&PerlX != 0 {
+ if len(t) > 0 && t[0] == '?' {
+ t = t[1:]
+ flags ^= NonGreedy
+ }
+ if lastRepeat != "" {
+ // In Perl it is not allowed to stack repetition operators:
+ // a** is a syntax error, not a doubled star, and a++ means
+ // something else entirely, which we don't support!
+ return "", &Error{ErrInvalidRepeatOp, lastRepeat[:len(lastRepeat)-len(t)]}
+ }
+ }
+ n := len(p.stack)
+ if n == 0 {
+ return "", &Error{ErrMissingRepeatArgument, opstr}
+ }
+ sub := p.stack[n-1]
+ re := &Regexp{
+ Op: op,
+ Min: min,
+ Max: max,
+ Flags: flags,
+ }
+ re.Sub = re.Sub0[:1]
+ re.Sub[0] = sub
+ p.stack[n-1] = re
+ return t, nil
+}
+
+// concat replaces the top of the stack (above the topmost '|' or '(') with its concatenation.
+func (p *parser) concat() *Regexp {
+ // TODO: Flatten concats.
+
+ // Scan down to find pseudo-operator | or (.
+ i := len(p.stack)
+ for i > 0 && p.stack[i-1].Op < opPseudo {
+ i--
+ }
+ sub := p.stack[i:]
+ p.stack = p.stack[:i]
+
+ var re *Regexp
+ switch len(sub) {
+ case 0:
+ re = &Regexp{Op: OpEmptyMatch}
+ case 1:
+ re = sub[0]
+ default:
+ re = &Regexp{Op: OpConcat}
+ re.Sub = append(re.Sub0[:0], sub...)
+ }
+ return p.push(re)
+}
+
+// alternate replaces the top of the stack (above the topmost '(') with its alternation.
+func (p *parser) alternate() *Regexp {
+ // TODO: Flatten alternates.
+
+ // Scan down to find pseudo-operator (.
+ // There are no | above (.
+ i := len(p.stack)
+ for i > 0 && p.stack[i-1].Op < opPseudo {
+ i--
+ }
+ sub := p.stack[i:]
+ p.stack = p.stack[:i]
+
+ var re *Regexp
+ switch len(sub) {
+ case 0:
+ re = &Regexp{Op: OpNoMatch}
+ case 1:
+ re = sub[0]
+ default:
+ re = &Regexp{Op: OpAlternate}
+ re.Sub = append(re.Sub0[:0], sub...)
+ }
+ return p.push(re)
+}
+
+func literalRegexp(s string, flags Flags) *Regexp {
+ re := &Regexp{
+ Op: OpLiteral,
+ Flags: flags,
+ }
+ re.Rune = re.Rune0[:0] // use local storage for small strings
+ for _, c := range s {
+ if len(re.Rune) >= cap(re.Rune) {
+ // string is too long to fit in Rune0. let Go handle it
+ re.Rune = []int(s)
+ break
+ }
+ re.Rune = append(re.Rune, c)
+ }
+ return re
+}
+
+// Parsing.
+
+func Parse(s string, flags Flags) (*Regexp, os.Error) {
+ if flags&Literal != 0 {
+ // Trivial parser for literal string.
+ if err := checkUTF8(s); err != nil {
+ return nil, err
+ }
+ return literalRegexp(s, flags), nil
+ }
+
+ // Otherwise, must do real work.
+ var (
+ p parser
+ err os.Error
+ c int
+ op Op
+ lastRepeat string
+ min, max int
+ )
+ p.flags = flags
+ p.wholeRegexp = s
+ t := s
+ for t != "" {
+ repeat := ""
+ BigSwitch:
+ switch t[0] {
+ default:
+ if c, t, err = nextRune(t); err != nil {
+ return nil, err
+ }
+ p.literal(c)
+
+ case '(':
+ if p.flags&PerlX != 0 && len(t) >= 2 && t[1] == '?' {
+ // Flag changes and non-capturing groups.
+ if t, err = p.parsePerlFlags(t); err != nil {
+ return nil, err
+ }
+ break
+ }
+ p.numCap++
+ p.op(opLeftParen).Cap = p.numCap
+ t = t[1:]
+ case '|':
+ p.concat()
+ if err = p.parseVerticalBar(); err != nil {
+ return nil, err
+ }
+ t = t[1:]
+ case ')':
+ if err = p.parseRightParen(); err != nil {
+ return nil, err
+ }
+ t = t[1:]
+ case '^':
+ if p.flags&OneLine != 0 {
+ p.op(OpBeginText)
+ } else {
+ p.op(OpBeginLine)
+ }
+ t = t[1:]
+ case '$':
+ if p.flags&OneLine != 0 {
+ p.op(OpEndText).Flags |= WasDollar
+ } else {
+ p.op(OpEndLine)
+ }
+ t = t[1:]
+ case '.':
+ if p.flags&DotNL != 0 {
+ p.op(OpAnyChar)
+ } else {
+ p.op(OpAnyCharNotNL)
+ }
+ t = t[1:]
+ case '[':
+ if t, err = p.parseClass(t); err != nil {
+ return nil, err
+ }
+ case '*', '+', '?':
+ switch t[0] {
+ case '*':
+ op = OpStar
+ case '+':
+ op = OpPlus
+ case '?':
+ op = OpQuest
+ }
+ if t, err = p.repeat(op, min, max, t[:1], t[1:], lastRepeat); err != nil {
+ return nil, err
+ }
+ case '{':
+ op = OpRepeat
+ min, max, tt, ok := p.parseRepeat(t)
+ if !ok {
+ // If the repeat cannot be parsed, { is a literal.
+ p.literal('{')
+ t = t[1:]
+ break
+ }
+ if t, err = p.repeat(op, min, max, t[:len(t)-len(tt)], tt, lastRepeat); err != nil {
+ return nil, err
+ }
+ case '\\':
+ if p.flags&PerlX != 0 && len(t) >= 2 {
+ switch t[1] {
+ case 'A':
+ p.op(OpBeginText)
+ t = t[2:]
+ break BigSwitch
+ case 'b':
+ p.op(OpWordBoundary)
+ t = t[2:]
+ break BigSwitch
+ case 'B':
+ p.op(OpNoWordBoundary)
+ t = t[2:]
+ break BigSwitch
+ case 'C':
+ // any byte; not supported
+ return nil, &Error{ErrInvalidEscape, t[:2]}
+ case 'Q':
+ // \Q ... \E: the ... is always literals
+ var lit string
+ if i := strings.Index(t, `\E`); i < 0 {
+ lit = t[2:]
+ t = ""
+ } else {
+ lit = t[2:i]
+ t = t[i+2:]
+ }
+ p.push(literalRegexp(lit, p.flags))
+ break BigSwitch
+ case 'z':
+ p.op(OpEndText)
+ t = t[2:]
+ break BigSwitch
+ }
+ }
+
+ re := &Regexp{Op: OpCharClass, Flags: p.flags}
+
+ // Look for Unicode character group like \p{Han}
+ if len(t) >= 2 && (t[1] == 'p' || t[1] == 'P') {
+ r, rest, err := p.parseUnicodeClass(t, re.Rune0[:0])
+ if err != nil {
+ return nil, err
+ }
+ if r != nil {
+ re.Rune = r
+ t = rest
+ // TODO: Handle FoldCase flag.
+ p.push(re)
+ break BigSwitch
+ }
+ }
+
+ // Perl character class escape.
+ if r, rest := p.parsePerlClassEscape(t, re.Rune0[:0]); r != nil {
+ re.Rune = r
+ t = rest
+ // TODO: Handle FoldCase flag.
+ p.push(re)
+ break BigSwitch
+ }
+
+ // TODO: Give re back to parser's pool.
+
+ // Ordinary single-character escape.
+ if c, t, err = p.parseEscape(t); err != nil {
+ return nil, err
+ }
+ p.literal(c)
+ }
+ lastRepeat = repeat
+ }
+
+ p.concat()
+ if p.swapVerticalBar() {
+ // pop vertical bar
+ p.stack = p.stack[:len(p.stack)-1]
+ }
+ p.alternate()
+
+ n := len(p.stack)
+ if n != 1 {
+ return nil, &Error{ErrMissingParen, s}
+ }
+ return p.stack[0], nil
+}
+
+// parseRepeat parses {min} (max=min) or {min,} (max=-1) or {min,max}.
+// If s is not of that form, it returns ok == false.
+func (p *parser) parseRepeat(s string) (min, max int, rest string, ok bool) {
+ if s == "" || s[0] != '{' {
+ return
+ }
+ s = s[1:]
+ if min, s, ok = p.parseInt(s); !ok {
+ return
+ }
+ if s == "" {
+ return
+ }
+ if s[0] != ',' {
+ max = min
+ } else {
+ s = s[1:]
+ if s == "" {
+ return
+ }
+ if s[0] == '}' {
+ max = -1
+ } else if max, s, ok = p.parseInt(s); !ok {
+ return
+ }
+ }
+ if s == "" || s[0] != '}' {
+ return
+ }
+ rest = s[1:]
+ ok = true
+ return
+}
+
+// parsePerlFlags parses a Perl flag setting or non-capturing group or both,
+// like (?i) or (?: or (?i:. It removes the prefix from s and updates the parse state.
+// The caller must have ensured that s begins with "(?".
+func (p *parser) parsePerlFlags(s string) (rest string, err os.Error) {
+ t := s
+
+ // Check for named captures, first introduced in Python's regexp library.
+ // As usual, there are three slightly different syntaxes:
+ //
+ // (?P<name>expr) the original, introduced by Python
+ // (?<name>expr) the .NET alteration, adopted by Perl 5.10
+ // (?'name'expr) another .NET alteration, adopted by Perl 5.10
+ //
+ // Perl 5.10 gave in and implemented the Python version too,
+ // but they claim that the last two are the preferred forms.
+ // PCRE and languages based on it (specifically, PHP and Ruby)
+ // support all three as well. EcmaScript 4 uses only the Python form.
+ //
+ // In both the open source world (via Code Search) and the
+ // Google source tree, (?P<expr>name) is the dominant form,
+ // so that's the one we implement. One is enough.
+ if len(t) > 4 && t[2] == 'P' && t[3] == '<' {
+ // Pull out name.
+ end := strings.IndexRune(t, '>')
+ if end < 0 {
+ if err = checkUTF8(t); err != nil {
+ return "", err
+ }
+ return "", &Error{ErrInvalidNamedCapture, s}
+ }
+
+ capture := t[:end+1] // "(?P<name>"
+ name := t[4:end] // "name"
+ if err = checkUTF8(name); err != nil {
+ return "", err
+ }
+ if !isValidCaptureName(name) {
+ return "", &Error{ErrInvalidNamedCapture, capture}
+ }
+
+ // Like ordinary capture, but named.
+ p.numCap++
+ re := p.op(opLeftParen)
+ re.Cap = p.numCap
+ re.Name = name
+ return t[end+1:], nil
+ }
+
+ // Non-capturing group. Might also twiddle Perl flags.
+ var c int
+ t = t[2:] // skip (?
+ flags := p.flags
+ sign := +1
+ sawFlag := false
+Loop:
+ for t != "" {
+ if c, t, err = nextRune(t); err != nil {
+ return "", err
+ }
+ switch c {
+ default:
+ break Loop
+
+ // Flags.
+ case 'i':
+ flags |= FoldCase
+ sawFlag = true
+ case 'm':
+ flags &^= OneLine
+ sawFlag = true
+ case 's':
+ flags |= DotNL
+ sawFlag = true
+ case 'U':
+ flags |= NonGreedy
+ sawFlag = true
+
+ // Switch to negation.
+ case '-':
+ if sign < 0 {
+ break Loop
+ }
+ sign = -1
+ // Invert flags so that | above turn into &^ and vice versa.
+ // We'll invert flags again before using it below.
+ flags = ^flags
+ sawFlag = false
+
+ // End of flags, starting group or not.
+ case ':', ')':
+ if sign < 0 {
+ if !sawFlag {
+ break Loop
+ }
+ flags = ^flags
+ }
+ if c == ':' {
+ // Open new group
+ p.op(opLeftParen)
+ }
+ p.flags = flags
+ return t, nil
+ }
+ }
+
+ return "", &Error{ErrInvalidPerlOp, s[:len(s)-len(t)]}
+}
+
+// isValidCaptureName reports whether name
+// is a valid capture name: [A-Za-z0-9_]+.
+// PCRE limits names to 32 bytes.
+// Python rejects names starting with digits.
+// We don't enforce either of those.
+func isValidCaptureName(name string) bool {
+ if name == "" {
+ return false
+ }
+ for _, c := range name {
+ if c != '_' && !isalnum(c) {
+ return false
+ }
+ }
+ return true
+}
+
+// parseInt parses a decimal integer.
+func (p *parser) parseInt(s string) (n int, rest string, ok bool) {
+ if s == "" || s[0] < '0' || '9' < s[0] {
+ return
+ }
+ // Disallow leading zeros.
+ if len(s) >= 2 && s[0] == '0' && '0' <= s[1] && s[1] <= '9' {
+ return
+ }
+ for s != "" && '0' <= s[0] && s[0] <= '9' {
+ // Avoid overflow.
+ if n >= 1e8 {
+ return
+ }
+ n = n*10 + int(s[0]) - '0'
+ s = s[1:]
+ }
+ rest = s
+ ok = true
+ return
+}
+
+// parseVerticalBar handles a | in the input.
+func (p *parser) parseVerticalBar() os.Error {
+ p.concat()
+
+ // The concatenation we just parsed is on top of the stack.
+ // If it sits above an opVerticalBar, swap it below
+ // (things below an opVerticalBar become an alternation).
+ // Otherwise, push a new vertical bar.
+ if !p.swapVerticalBar() {
+ p.op(opVerticalBar)
+ }
+
+ return nil
+}
+
+// If the top of the stack is an element followed by an opVerticalBar
+// swapVerticalBar swaps the two and returns true.
+// Otherwise it returns false.
+func (p *parser) swapVerticalBar() bool {
+ if n := len(p.stack); n >= 2 {
+ re1 := p.stack[n-1]
+ re2 := p.stack[n-2]
+ if re2.Op == opVerticalBar {
+ p.stack[n-2] = re1
+ p.stack[n-1] = re2
+ return true
+ }
+ }
+ return false
+}
+
+// parseRightParen handles a ) in the input.
+func (p *parser) parseRightParen() os.Error {
+ p.concat()
+ if p.swapVerticalBar() {
+ // pop vertical bar
+ p.stack = p.stack[:len(p.stack)-1]
+ }
+ p.alternate()
+
+ n := len(p.stack)
+ if n < 2 {
+ return &Error{ErrInternalError, ""}
+ }
+ re1 := p.stack[n-1]
+ re2 := p.stack[n-2]
+ p.stack = p.stack[:n-2]
+ if re2.Op != opLeftParen {
+ return &Error{ErrMissingParen, p.wholeRegexp}
+ }
+ if re2.Cap == 0 {
+ // Just for grouping.
+ p.push(re1)
+ } else {
+ re2.Op = OpCapture
+ re2.Sub = re2.Sub0[:1]
+ re2.Sub[0] = re1
+ p.push(re2)
+ }
+ return nil
+}
+
+// parseEscape parses an escape sequence at the beginning of s
+// and returns the rune.
+func (p *parser) parseEscape(s string) (r int, rest string, err os.Error) {
+ t := s[1:]
+ if t == "" {
+ return 0, "", &Error{ErrTrailingBackslash, ""}
+ }
+ c, t, err := nextRune(t)
+ if err != nil {
+ return 0, "", err
+ }
+
+Switch:
+ switch c {
+ default:
+ if c < utf8.RuneSelf && !isalnum(c) {
+ // Escaped non-word characters are always themselves.
+ // PCRE is not quite so rigorous: it accepts things like
+ // \q, but we don't. We once rejected \_, but too many
+ // programs and people insist on using it, so allow \_.
+ return c, t, nil
+ }
+
+ // Octal escapes.
+ case '1', '2', '3', '4', '5', '6', '7':
+ // Single non-zero digit is a backreference; not supported
+ if t == "" || t[0] < '0' || t[0] > '7' {
+ break
+ }
+ fallthrough
+ case '0':
+ // Consume up to three octal digits; already have one.
+ r = c - '0'
+ for i := 1; i < 3; i++ {
+ if t == "" || t[0] < '0' || t[0] > '7' {
+ break
+ }
+ r = r*8 + int(t[0]) - '0'
+ t = t[1:]
+ }
+ return r, t, nil
+
+ // Hexadecimal escapes.
+ case 'x':
+ if t == "" {
+ break
+ }
+ if c, t, err = nextRune(t); err != nil {
+ return 0, "", err
+ }
+ if c == '{' {
+ // Any number of digits in braces.
+ // Perl accepts any text at all; it ignores all text
+ // after the first non-hex digit. We require only hex digits,
+ // and at least one.
+ nhex := 0
+ r = 0
+ for {
+ if t == "" {
+ break Switch
+ }
+ if c, t, err = nextRune(t); err != nil {
+ return 0, "", err
+ }
+ if c == '}' {
+ break
+ }
+ v := unhex(c)
+ if v < 0 {
+ break Switch
+ }
+ r = r*16 + v
+ if r > unicode.MaxRune {
+ break Switch
+ }
+ }
+ if nhex == 0 {
+ break Switch
+ }
+ return r, t, nil
+ }
+
+ // Easy case: two hex digits.
+ x := unhex(c)
+ if c, t, err = nextRune(t); err != nil {
+ return 0, "", err
+ }
+ y := unhex(c)
+ if x < 0 || y < 0 {
+ break
+ }
+ return x*16 + y, t, nil
+
+ // C escapes. There is no case 'b', to avoid misparsing
+ // the Perl word-boundary \b as the C backspace \b
+ // when in POSIX mode. In Perl, /\b/ means word-boundary
+ // but /[\b]/ means backspace. We don't support that.
+ // If you want a backspace, embed a literal backspace
+ // character or use \x08.
+ case 'a':
+ return '\a', t, err
+ case 'f':
+ return '\f', t, err
+ case 'n':
+ return '\n', t, err
+ case 'r':
+ return '\r', t, err
+ case 't':
+ return '\t', t, err
+ case 'v':
+ return '\v', t, err
+ }
+ return 0, "", &Error{ErrInvalidEscape, s[:len(s)-len(t)]}
+}
+
+// parseClassChar parses a character class character at the beginning of s
+// and returns it.
+func (p *parser) parseClassChar(s, wholeClass string) (r int, rest string, err os.Error) {
+ if s == "" {
+ return 0, "", &Error{Code: ErrMissingBracket, Expr: wholeClass}
+ }
+
+ // Allow regular escape sequences even though
+ // many need not be escaped in this context.
+ if s[0] == '\\' {
+ return p.parseEscape(s)
+ }
+
+ return nextRune(s)
+}
+
+type charGroup struct {
+ sign int
+ class []int
+}
+
+// parsePerlClassEscape parses a leading Perl character class escape like \d
+// from the beginning of s. If one is present, it appends the characters to r
+// and returns the new slice r and the remainder of the string.
+func (p *parser) parsePerlClassEscape(s string, r []int) (out []int, rest string) {
+ if p.flags&PerlX == 0 || len(s) < 2 || s[0] != '\\' {
+ return
+ }
+ g := perlGroup[s[0:2]]
+ if g.sign == 0 {
+ return
+ }
+ if g.sign < 0 {
+ r = appendNegatedClass(r, g.class)
+ } else {
+ r = appendClass(r, g.class)
+ }
+ return r, s[2:]
+}
+
+// parseNamedClass parses a leading POSIX named character class like [:alnum:]
+// from the beginning of s. If one is present, it appends the characters to r
+// and returns the new slice r and the remainder of the string.
+func (p *parser) parseNamedClass(s string, r []int) (out []int, rest string, err os.Error) {
+ if len(s) < 2 || s[0] != '[' || s[1] != ':' {
+ return
+ }
+
+ i := strings.Index(s[2:], ":]")
+ if i < 0 {
+ return
+ }
+ i += 2
+ name, s := s[0:i+2], s[i+2:]
+ g := posixGroup[name]
+ if g.sign == 0 {
+ return nil, "", &Error{ErrInvalidCharRange, name}
+ }
+ if g.sign < 0 {
+ r = appendNegatedClass(r, g.class)
+ } else {
+ r = appendClass(r, g.class)
+ }
+ return r, s, nil
+}
+
+// unicodeTable returns the unicode.RangeTable identified by name.
+func unicodeTable(name string) *unicode.RangeTable {
+ if t := unicode.Categories[name]; t != nil {
+ return t
+ }
+ if t := unicode.Scripts[name]; t != nil {
+ return t
+ }
+ return nil
+}
+
+// parseUnicodeClass parses a leading Unicode character class like \p{Han}
+// from the beginning of s. If one is present, it appends the characters to r
+// and returns the new slice r and the remainder of the string.
+func (p *parser) parseUnicodeClass(s string, r []int) (out []int, rest string, err os.Error) {
+ if p.flags&UnicodeGroups == 0 || len(s) < 2 || s[0] != '\\' || s[1] != 'p' && s[1] != 'P' {
+ return
+ }
+
+ // Committed to parse or return error.
+ sign := +1
+ if s[1] == 'P' {
+ sign = -1
+ }
+ t := s[2:]
+ c, t, err := nextRune(t)
+ if err != nil {
+ return
+ }
+ var seq, name string
+ if c != '{' {
+ // Single-letter name.
+ seq = s[:len(s)-len(t)]
+ name = seq[2:]
+ } else {
+ // Name is in braces.
+ end := strings.IndexRune(s, '}')
+ if end < 0 {
+ if err = checkUTF8(s); err != nil {
+ return
+ }
+ return nil, "", &Error{ErrInvalidCharRange, s}
+ }
+ seq, t = s[:end+1], s[end+1:]
+ name = s[3:end]
+ if err = checkUTF8(name); err != nil {
+ return
+ }
+ }
+
+ // Group can have leading negation too. \p{^Han} == \P{Han}, \P{^Han} == \p{Han}.
+ if name != "" && name[0] == '^' {
+ sign = -sign
+ name = name[1:]
+ }
+
+ tab := unicodeTable(name)
+ if tab == nil {
+ return nil, "", &Error{ErrInvalidCharRange, seq}
+ }
+ if sign > 0 {
+ r = appendTable(r, tab)
+ } else {
+ r = appendNegatedTable(r, tab)
+ }
+ return r, t, nil
+}
+
+// parseClass parses a character class at the beginning of s
+// and pushes it onto the parse stack.
+func (p *parser) parseClass(s string) (rest string, err os.Error) {
+ t := s[1:] // chop [
+ re := &Regexp{Op: OpCharClass, Flags: p.flags}
+ re.Rune = re.Rune0[:0]
+
+ sign := +1
+ if t != "" && t[0] == '^' {
+ sign = -1
+ t = t[1:]
+
+ // If character class does not match \n, add it here,
+ // so that negation later will do the right thing.
+ if p.flags&ClassNL == 0 {
+ re.Rune = append(re.Rune, '\n', '\n')
+ }
+ }
+
+ class := re.Rune
+ first := true // ] and - are okay as first char in class
+ for t == "" || t[0] != ']' || first {
+ // POSIX: - is only okay unescaped as first or last in class.
+ // Perl: - is okay anywhere.
+ if t != "" && t[0] == '-' && p.flags&PerlX == 0 && !first && (len(t) == 1 || t[1] != ']') {
+ _, size := utf8.DecodeRuneInString(t[1:])
+ return "", &Error{Code: ErrInvalidCharRange, Expr: t[:1+size]}
+ }
+ first = false
+
+ // Look for POSIX [:alnum:] etc.
+ if len(t) > 2 && t[0] == '[' && t[1] == ':' {
+ nclass, nt, err := p.parseNamedClass(t, class)
+ if err != nil {
+ return "", err
+ }
+ if nclass != nil {
+ class, t = nclass, nt
+ continue
+ }
+ }
+
+ // Look for Unicode character group like \p{Han}.
+ nclass, nt, err := p.parseUnicodeClass(t, class)
+ if err != nil {
+ return "", err
+ }
+ if nclass != nil {
+ class, t = nclass, nt
+ continue
+ }
+
+ // Look for Perl character class symbols (extension).
+ if nclass, nt := p.parsePerlClassEscape(t, class); nclass != nil {
+ class, t = nclass, nt
+ continue
+ }
+
+ // Single character or simple range.
+ rng := t
+ var lo, hi int
+ if lo, t, err = p.parseClassChar(t, s); err != nil {
+ return "", err
+ }
+ hi = lo
+ // [a-] means (a|-) so check for final ].
+ if len(t) >= 2 && t[0] == '-' && t[1] != ']' {
+ t = t[1:]
+ if hi, t, err = p.parseClassChar(t, s); err != nil {
+ return "", err
+ }
+ if hi < lo {
+ rng = rng[:len(rng)-len(t)]
+ return "", &Error{Code: ErrInvalidCharRange, Expr: rng}
+ }
+ }
+ class = appendRange(class, lo, hi)
+ }
+ t = t[1:] // chop ]
+
+ // TODO: Handle FoldCase flag.
+
+ // Use &re.Rune instead of &class to avoid allocation.
+ re.Rune = class
+ class = cleanClass(&re.Rune)
+ if sign < 0 {
+ class = negateClass(class)
+ }
+ re.Rune = class
+ p.push(re)
+ return t, nil
+}
+
+// cleanClass sorts the ranges (pairs of elements of r),
+// merges them, and eliminates duplicates.
+func cleanClass(rp *[]int) []int {
+ // Sort by lo increasing, hi decreasing to break ties.
+ sort.Sort(ranges{rp})
+
+ r := *rp
+ // Merge abutting, overlapping.
+ w := 2 // write index
+ for i := 2; i < len(r); i += 2 {
+ lo, hi := r[i], r[i+1]
+ if lo <= r[w-1]+1 {
+ // merge with previous range
+ if hi > r[w-1] {
+ r[w-1] = hi
+ }
+ continue
+ }
+ // new disjoint range
+ r[w] = lo
+ r[w+1] = hi
+ w += 2
+ }
+
+ return r[:w]
+}
+
+// appendRange returns the result of appending the range lo-hi to the class r.
+func appendRange(r []int, lo, hi int) []int {
+ // Expand last range if overlaps or abuts.
+ if n := len(r); n > 0 {
+ rlo, rhi := r[n-2], r[n-1]
+ if lo <= rhi+1 && rlo <= hi+1 {
+ if lo < rlo {
+ r[n-2] = lo
+ }
+ if hi > rhi {
+ r[n-1] = hi
+ }
+ return r
+ }
+ }
+
+ return append(r, lo, hi)
+}
+
+// appendClass returns the result of appending the class x to the class r.
+// It assume x is clean.
+func appendClass(r []int, x []int) []int {
+ for i := 0; i < len(x); i += 2 {
+ r = appendRange(r, x[i], x[i+1])
+ }
+ return r
+}
+
+// appendNegatedClass returns the result of appending the negation of the class x to the class r.
+// It assumes x is clean.
+func appendNegatedClass(r []int, x []int) []int {
+ nextLo := 0
+ for i := 0; i < len(x); i += 2 {
+ lo, hi := x[i], x[i+1]
+ if nextLo <= lo-1 {
+ r = appendRange(r, nextLo, lo-1)
+ }
+ nextLo = hi + 1
+ }
+ if nextLo <= unicode.MaxRune {
+ r = appendRange(r, nextLo, unicode.MaxRune)
+ }
+ return r
+}
+
+// appendTable returns the result of appending x to the class r.
+func appendTable(r []int, x *unicode.RangeTable) []int {
+ for _, xr := range x.R16 {
+ lo, hi, stride := int(xr.Lo), int(xr.Hi), int(xr.Stride)
+ if stride == 1 {
+ r = appendRange(r, lo, hi)
+ continue
+ }
+ for c := lo; c <= hi; c += stride {
+ r = appendRange(r, c, c)
+ }
+ }
+ for _, xr := range x.R32 {
+ lo, hi, stride := int(xr.Lo), int(xr.Hi), int(xr.Stride)
+ if stride == 1 {
+ r = appendRange(r, lo, hi)
+ continue
+ }
+ for c := lo; c <= hi; c += stride {
+ r = appendRange(r, c, c)
+ }
+ }
+ return r
+}
+
+// appendNegatedTable returns the result of appending the negation of x to the class r.
+func appendNegatedTable(r []int, x *unicode.RangeTable) []int {
+ nextLo := 0 // lo end of next class to add
+ for _, xr := range x.R16 {
+ lo, hi, stride := int(xr.Lo), int(xr.Hi), int(xr.Stride)
+ if stride == 1 {
+ if nextLo <= lo-1 {
+ r = appendRange(r, nextLo, lo-1)
+ }
+ nextLo = hi + 1
+ continue
+ }
+ for c := lo; c <= hi; c += stride {
+ if nextLo <= c-1 {
+ r = appendRange(r, nextLo, c-1)
+ }
+ nextLo = c + 1
+ }
+ }
+ for _, xr := range x.R32 {
+ lo, hi, stride := int(xr.Lo), int(xr.Hi), int(xr.Stride)
+ if stride == 1 {
+ if nextLo <= lo-1 {
+ r = appendRange(r, nextLo, lo-1)
+ }
+ nextLo = hi + 1
+ continue
+ }
+ for c := lo; c <= hi; c += stride {
+ if nextLo <= c-1 {
+ r = appendRange(r, nextLo, c-1)
+ }
+ nextLo = c + 1
+ }
+ }
+ if nextLo <= unicode.MaxRune {
+ r = appendRange(r, nextLo, unicode.MaxRune)
+ }
+ return r
+}
+
+// negateClass overwrites r and returns r's negation.
+// It assumes the class r is already clean.
+func negateClass(r []int) []int {
+ nextLo := 0 // lo end of next class to add
+ w := 0 // write index
+ for i := 0; i < len(r); i += 2 {
+ lo, hi := r[i], r[i+1]
+ if nextLo <= lo-1 {
+ r[w] = nextLo
+ r[w+1] = lo - 1
+ w += 2
+ }
+ nextLo = hi + 1
+ }
+ if nextLo <= unicode.MaxRune {
+ // It's possible for the negation to have one more
+ // range - this one - than the original class, so use append.
+ r = append(r[:w], nextLo, unicode.MaxRune)
+ }
+ return r
+}
+
+// ranges implements sort.Interface on a []rune.
+// The choice of receiver type definition is strange
+// but avoids an allocation since we already have
+// a *[]int.
+type ranges struct {
+ p *[]int
+}
+
+func (ra ranges) Less(i, j int) bool {
+ p := *ra.p
+ i *= 2
+ j *= 2
+ return p[i] < p[j] || p[i] == p[j] && p[i+1] > p[j+1]
+}
+
+func (ra ranges) Len() int {
+ return len(*ra.p) / 2
+}
+
+func (ra ranges) Swap(i, j int) {
+ p := *ra.p
+ i *= 2
+ j *= 2
+ p[i], p[i+1], p[j], p[j+1] = p[j], p[j+1], p[i], p[i+1]
+}
+
+
+func checkUTF8(s string) os.Error {
+ for s != "" {
+ rune, size := utf8.DecodeRuneInString(s)
+ if rune == utf8.RuneError && size == 1 {
+ return &Error{Code: ErrInvalidUTF8, Expr: s}
+ }
+ s = s[size:]
+ }
+ return nil
+}
+
+func nextRune(s string) (c int, t string, err os.Error) {
+ c, size := utf8.DecodeRuneInString(s)
+ if c == utf8.RuneError && size == 1 {
+ return 0, "", &Error{Code: ErrInvalidUTF8, Expr: s}
+ }
+ return c, s[size:], nil
+}
+
+func isalnum(c int) bool {
+ return '0' <= c && c <= '9' || 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z'
+}
+
+func unhex(c int) int {
+ if '0' <= c && c <= '9' {
+ return c - '0'
+ }
+ if 'a' <= c && c <= 'f' {
+ return c - 'a' + 10
+ }
+ if 'A' <= c && c <= 'F' {
+ return c - 'A' + 10
+ }
+ return -1
+}
diff --git a/src/pkg/exp/regexp/syntax/parse_test.go b/src/pkg/exp/regexp/syntax/parse_test.go
new file mode 100644
index 000000000..b52cab1a1
--- /dev/null
+++ b/src/pkg/exp/regexp/syntax/parse_test.go
@@ -0,0 +1,272 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syntax
+
+import (
+ "bytes"
+ "fmt"
+ "testing"
+ "unicode"
+)
+
+var parseTests = []struct {
+ Regexp string
+ Dump string
+}{
+ // Base cases
+ {"a", "lit{a}"},
+ {"a.", "cat{lit{a}dot{}}"},
+ {"a.b", "cat{lit{a}dot{}lit{b}}"},
+ // { "ab", "str{ab}" },
+ {"ab", "cat{lit{a}lit{b}}"},
+ {"a.b.c", "cat{lit{a}dot{}lit{b}dot{}lit{c}}"},
+ // { "abc", "str{abc}" },
+ {"abc", "cat{lit{a}lit{b}lit{c}}"},
+ {"a|^", "alt{lit{a}bol{}}"},
+ // { "a|b", "cc{0x61-0x62}" },
+ {"a|b", "alt{lit{a}lit{b}}"},
+ {"(a)", "cap{lit{a}}"},
+ {"(a)|b", "alt{cap{lit{a}}lit{b}}"},
+ {"a*", "star{lit{a}}"},
+ {"a+", "plus{lit{a}}"},
+ {"a?", "que{lit{a}}"},
+ {"a{2}", "rep{2,2 lit{a}}"},
+ {"a{2,3}", "rep{2,3 lit{a}}"},
+ {"a{2,}", "rep{2,-1 lit{a}}"},
+ {"a*?", "nstar{lit{a}}"},
+ {"a+?", "nplus{lit{a}}"},
+ {"a??", "nque{lit{a}}"},
+ {"a{2}?", "nrep{2,2 lit{a}}"},
+ {"a{2,3}?", "nrep{2,3 lit{a}}"},
+ {"a{2,}?", "nrep{2,-1 lit{a}}"},
+ {"", "emp{}"},
+ // { "|", "emp{}" }, // alt{emp{}emp{}} but got factored
+ {"|", "alt{emp{}emp{}}"},
+ {"|x|", "alt{emp{}lit{x}emp{}}"},
+ {".", "dot{}"},
+ {"^", "bol{}"},
+ {"$", "eol{}"},
+ {"\\|", "lit{|}"},
+ {"\\(", "lit{(}"},
+ {"\\)", "lit{)}"},
+ {"\\*", "lit{*}"},
+ {"\\+", "lit{+}"},
+ {"\\?", "lit{?}"},
+ {"{", "lit{{}"},
+ {"}", "lit{}}"},
+ {"\\.", "lit{.}"},
+ {"\\^", "lit{^}"},
+ {"\\$", "lit{$}"},
+ {"\\\\", "lit{\\}"},
+ {"[ace]", "cc{0x61 0x63 0x65}"},
+ {"[abc]", "cc{0x61-0x63}"},
+ {"[a-z]", "cc{0x61-0x7a}"},
+ // { "[a]", "lit{a}" },
+ {"[a]", "cc{0x61}"},
+ {"\\-", "lit{-}"},
+ {"-", "lit{-}"},
+ {"\\_", "lit{_}"},
+
+ // Posix and Perl extensions
+ {"[[:lower:]]", "cc{0x61-0x7a}"},
+ {"[a-z]", "cc{0x61-0x7a}"},
+ {"[^[:lower:]]", "cc{0x0-0x60 0x7b-0x10ffff}"},
+ {"[[:^lower:]]", "cc{0x0-0x60 0x7b-0x10ffff}"},
+ // { "(?i)[[:lower:]]", "cc{0x41-0x5a 0x61-0x7a 0x17f 0x212a}" },
+ // { "(?i)[a-z]", "cc{0x41-0x5a 0x61-0x7a 0x17f 0x212a}" },
+ // { "(?i)[^[:lower:]]", "cc{0x0-0x40 0x5b-0x60 0x7b-0x17e 0x180-0x2129 0x212b-0x10ffff}" },
+ // { "(?i)[[:^lower:]]", "cc{0x0-0x40 0x5b-0x60 0x7b-0x17e 0x180-0x2129 0x212b-0x10ffff}" },
+ {"\\d", "cc{0x30-0x39}"},
+ {"\\D", "cc{0x0-0x2f 0x3a-0x10ffff}"},
+ {"\\s", "cc{0x9-0xa 0xc-0xd 0x20}"},
+ {"\\S", "cc{0x0-0x8 0xb 0xe-0x1f 0x21-0x10ffff}"},
+ {"\\w", "cc{0x30-0x39 0x41-0x5a 0x5f 0x61-0x7a}"},
+ {"\\W", "cc{0x0-0x2f 0x3a-0x40 0x5b-0x5e 0x60 0x7b-0x10ffff}"},
+ // { "(?i)\\w", "cc{0x30-0x39 0x41-0x5a 0x5f 0x61-0x7a 0x17f 0x212a}" },
+ // { "(?i)\\W", "cc{0x0-0x2f 0x3a-0x40 0x5b-0x5e 0x60 0x7b-0x17e 0x180-0x2129 0x212b-0x10ffff}" },
+ {"[^\\\\]", "cc{0x0-0x5b 0x5d-0x10ffff}"},
+ // { "\\C", "byte{}" },
+
+ // Unicode, negatives, and a double negative.
+ {"\\p{Braille}", "cc{0x2800-0x28ff}"},
+ {"\\P{Braille}", "cc{0x0-0x27ff 0x2900-0x10ffff}"},
+ {"\\p{^Braille}", "cc{0x0-0x27ff 0x2900-0x10ffff}"},
+ {"\\P{^Braille}", "cc{0x2800-0x28ff}"},
+ {"\\pZ", "cc{0x20 0xa0 0x1680 0x180e 0x2000-0x200a 0x2028-0x2029 0x202f 0x205f 0x3000}"},
+ {"[\\p{Braille}]", "cc{0x2800-0x28ff}"},
+ {"[\\P{Braille}]", "cc{0x0-0x27ff 0x2900-0x10ffff}"},
+ {"[\\p{^Braille}]", "cc{0x0-0x27ff 0x2900-0x10ffff}"},
+ {"[\\P{^Braille}]", "cc{0x2800-0x28ff}"},
+ {"[\\pZ]", "cc{0x20 0xa0 0x1680 0x180e 0x2000-0x200a 0x2028-0x2029 0x202f 0x205f 0x3000}"},
+
+ // More interesting regular expressions.
+ // { "a{,2}", "str{a{,2}}" },
+ // { "\\.\\^\\$\\\\", "str{.^$\\}" },
+ {"[a-zABC]", "cc{0x41-0x43 0x61-0x7a}"},
+ {"[^a]", "cc{0x0-0x60 0x62-0x10ffff}"},
+ {"[\xce\xb1-\xce\xb5\xe2\x98\xba]", "cc{0x3b1-0x3b5 0x263a}"}, // utf-8
+ {"a*{", "cat{star{lit{a}}lit{{}}"},
+
+ // Test precedences
+ // { "(?:ab)*", "star{str{ab}}" },
+ // { "(ab)*", "star{cap{str{ab}}}" },
+ // { "ab|cd", "alt{str{ab}str{cd}}" },
+ // { "a(b|c)d", "cat{lit{a}cap{cc{0x62-0x63}}lit{d}}" },
+ {"(?:ab)*", "star{cat{lit{a}lit{b}}}"},
+ {"(ab)*", "star{cap{cat{lit{a}lit{b}}}}"},
+ {"ab|cd", "alt{cat{lit{a}lit{b}}cat{lit{c}lit{d}}}"},
+ {"a(b|c)d", "cat{lit{a}cap{alt{lit{b}lit{c}}}lit{d}}"},
+
+ // Test flattening.
+ {"(?:a)", "lit{a}"},
+ // { "(?:ab)(?:cd)", "str{abcd}" },
+ // { "(?:a|b)|(?:c|d)", "cc{0x61-0x64}" },
+ // { "a|.", "dot{}" },
+ // { ".|a", "dot{}" },
+
+ // Test Perl quoted literals
+ {"\\Q+|*?{[\\E", "str{+|*?{[}"},
+ {"\\Q+\\E+", "plus{lit{+}}"},
+ {"\\Q\\\\E", "lit{\\}"},
+ {"\\Q\\\\\\E", "str{\\\\}"},
+
+ // Test Perl \A and \z
+ {"(?m)^", "bol{}"},
+ {"(?m)$", "eol{}"},
+ {"(?-m)^", "bot{}"},
+ {"(?-m)$", "eot{}"},
+ {"(?m)\\A", "bot{}"},
+ {"(?m)\\z", "eot{\\z}"},
+ {"(?-m)\\A", "bot{}"},
+ {"(?-m)\\z", "eot{\\z}"},
+
+ // Test named captures
+ {"(?P<name>a)", "cap{name:lit{a}}"},
+
+ // Case-folded literals
+ // { "[Aa]", "litfold{a}" },
+
+ // Strings
+ // { "abcde", "str{abcde}" },
+ // { "[Aa][Bb]cd", "cat{strfold{ab}str{cd}}" },
+}
+
+const testFlags = MatchNL | PerlX | UnicodeGroups
+
+// Test Parse -> Dump.
+func TestParseDump(t *testing.T) {
+ for _, tt := range parseTests {
+ re, err := Parse(tt.Regexp, testFlags)
+ if err != nil {
+ t.Errorf("Parse(%#q): %v", tt.Regexp, err)
+ continue
+ }
+ d := dump(re)
+ if d != tt.Dump {
+ t.Errorf("Parse(%#q).Dump() = %#q want %#q", tt.Regexp, d, tt.Dump)
+ }
+ }
+}
+
+// dump prints a string representation of the regexp showing
+// the structure explicitly.
+func dump(re *Regexp) string {
+ var b bytes.Buffer
+ dumpRegexp(&b, re)
+ return b.String()
+}
+
+var opNames = []string{
+ OpNoMatch: "no",
+ OpEmptyMatch: "emp",
+ OpLiteral: "lit",
+ OpCharClass: "cc",
+ OpAnyCharNotNL: "dnl",
+ OpAnyChar: "dot",
+ OpBeginLine: "bol",
+ OpEndLine: "eol",
+ OpBeginText: "bot",
+ OpEndText: "eot",
+ OpWordBoundary: "wb",
+ OpNoWordBoundary: "nwb",
+ OpCapture: "cap",
+ OpStar: "star",
+ OpPlus: "plus",
+ OpQuest: "que",
+ OpRepeat: "rep",
+ OpConcat: "cat",
+ OpAlternate: "alt",
+}
+
+// dumpRegexp writes an encoding of the syntax tree for the regexp re to b.
+// It is used during testing to distinguish between parses that might print
+// the same using re's String method.
+func dumpRegexp(b *bytes.Buffer, re *Regexp) {
+ if int(re.Op) >= len(opNames) || opNames[re.Op] == "" {
+ fmt.Fprintf(b, "op%d", re.Op)
+ } else {
+ switch re.Op {
+ default:
+ b.WriteString(opNames[re.Op])
+ case OpStar, OpPlus, OpQuest, OpRepeat:
+ if re.Flags&NonGreedy != 0 {
+ b.WriteByte('n')
+ }
+ b.WriteString(opNames[re.Op])
+ case OpLiteral:
+ if len(re.Rune) > 1 {
+ b.WriteString("str")
+ } else {
+ b.WriteString("lit")
+ }
+ if re.Flags&FoldCase != 0 {
+ for _, r := range re.Rune {
+ if unicode.ToUpper(r) != r {
+ b.WriteString("fold")
+ }
+ }
+ }
+ }
+ }
+ b.WriteByte('{')
+ switch re.Op {
+ case OpEndText:
+ if re.Flags&WasDollar == 0 {
+ b.WriteString(`\z`)
+ }
+ case OpLiteral:
+ for _, r := range re.Rune {
+ b.WriteRune(r)
+ }
+ case OpConcat, OpAlternate:
+ for _, sub := range re.Sub {
+ dumpRegexp(b, sub)
+ }
+ case OpStar, OpPlus, OpQuest:
+ dumpRegexp(b, re.Sub[0])
+ case OpRepeat:
+ fmt.Fprintf(b, "%d,%d ", re.Min, re.Max)
+ dumpRegexp(b, re.Sub[0])
+ case OpCapture:
+ if re.Name != "" {
+ b.WriteString(re.Name)
+ b.WriteByte(':')
+ }
+ dumpRegexp(b, re.Sub[0])
+ case OpCharClass:
+ sep := ""
+ for i := 0; i < len(re.Rune); i += 2 {
+ b.WriteString(sep)
+ sep = " "
+ lo, hi := re.Rune[i], re.Rune[i+1]
+ if lo == hi {
+ fmt.Fprintf(b, "%#x", lo)
+ } else {
+ fmt.Fprintf(b, "%#x-%#x", lo, hi)
+ }
+ }
+ }
+ b.WriteByte('}')
+}
diff --git a/src/pkg/exp/regexp/syntax/perl_groups.go b/src/pkg/exp/regexp/syntax/perl_groups.go
new file mode 100644
index 000000000..05b392c40
--- /dev/null
+++ b/src/pkg/exp/regexp/syntax/perl_groups.go
@@ -0,0 +1,130 @@
+// GENERATED BY make_perl_groups.pl; DO NOT EDIT.
+// make_perl_groups.pl >perl_groups.go
+
+package syntax
+
+var code1 = []int{ /* \d */
+ 0x30, 0x39,
+}
+
+var code2 = []int{ /* \s */
+ 0x9, 0xa,
+ 0xc, 0xd,
+ 0x20, 0x20,
+}
+
+var code3 = []int{ /* \w */
+ 0x30, 0x39,
+ 0x41, 0x5a,
+ 0x5f, 0x5f,
+ 0x61, 0x7a,
+}
+
+var perlGroup = map[string]charGroup{
+ `\d`: {+1, code1},
+ `\D`: {-1, code1},
+ `\s`: {+1, code2},
+ `\S`: {-1, code2},
+ `\w`: {+1, code3},
+ `\W`: {-1, code3},
+}
+var code4 = []int{ /* [:alnum:] */
+ 0x30, 0x39,
+ 0x41, 0x5a,
+ 0x61, 0x7a,
+}
+
+var code5 = []int{ /* [:alpha:] */
+ 0x41, 0x5a,
+ 0x61, 0x7a,
+}
+
+var code6 = []int{ /* [:ascii:] */
+ 0x0, 0x7f,
+}
+
+var code7 = []int{ /* [:blank:] */
+ 0x9, 0x9,
+ 0x20, 0x20,
+}
+
+var code8 = []int{ /* [:cntrl:] */
+ 0x0, 0x1f,
+ 0x7f, 0x7f,
+}
+
+var code9 = []int{ /* [:digit:] */
+ 0x30, 0x39,
+}
+
+var code10 = []int{ /* [:graph:] */
+ 0x21, 0x7e,
+}
+
+var code11 = []int{ /* [:lower:] */
+ 0x61, 0x7a,
+}
+
+var code12 = []int{ /* [:print:] */
+ 0x20, 0x7e,
+}
+
+var code13 = []int{ /* [:punct:] */
+ 0x21, 0x2f,
+ 0x3a, 0x40,
+ 0x5b, 0x60,
+ 0x7b, 0x7e,
+}
+
+var code14 = []int{ /* [:space:] */
+ 0x9, 0xd,
+ 0x20, 0x20,
+}
+
+var code15 = []int{ /* [:upper:] */
+ 0x41, 0x5a,
+}
+
+var code16 = []int{ /* [:word:] */
+ 0x30, 0x39,
+ 0x41, 0x5a,
+ 0x5f, 0x5f,
+ 0x61, 0x7a,
+}
+
+var code17 = []int{ /* [:xdigit:] */
+ 0x30, 0x39,
+ 0x41, 0x46,
+ 0x61, 0x66,
+}
+
+var posixGroup = map[string]charGroup{
+ `[:alnum:]`: {+1, code4},
+ `[:^alnum:]`: {-1, code4},
+ `[:alpha:]`: {+1, code5},
+ `[:^alpha:]`: {-1, code5},
+ `[:ascii:]`: {+1, code6},
+ `[:^ascii:]`: {-1, code6},
+ `[:blank:]`: {+1, code7},
+ `[:^blank:]`: {-1, code7},
+ `[:cntrl:]`: {+1, code8},
+ `[:^cntrl:]`: {-1, code8},
+ `[:digit:]`: {+1, code9},
+ `[:^digit:]`: {-1, code9},
+ `[:graph:]`: {+1, code10},
+ `[:^graph:]`: {-1, code10},
+ `[:lower:]`: {+1, code11},
+ `[:^lower:]`: {-1, code11},
+ `[:print:]`: {+1, code12},
+ `[:^print:]`: {-1, code12},
+ `[:punct:]`: {+1, code13},
+ `[:^punct:]`: {-1, code13},
+ `[:space:]`: {+1, code14},
+ `[:^space:]`: {-1, code14},
+ `[:upper:]`: {+1, code15},
+ `[:^upper:]`: {-1, code15},
+ `[:word:]`: {+1, code16},
+ `[:^word:]`: {-1, code16},
+ `[:xdigit:]`: {+1, code17},
+ `[:^xdigit:]`: {-1, code17},
+}
diff --git a/src/pkg/exp/regexp/syntax/regexp.go b/src/pkg/exp/regexp/syntax/regexp.go
new file mode 100644
index 000000000..a0c465967
--- /dev/null
+++ b/src/pkg/exp/regexp/syntax/regexp.go
@@ -0,0 +1,210 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package syntax parses regular expressions into syntax trees.
+// WORK IN PROGRESS.
+package syntax
+
+// Note to implementers:
+// In this package, re is always a *Regexp and r is always a rune.
+
+import (
+ "bytes"
+ "strconv"
+ "strings"
+ "unicode"
+)
+
+// A Regexp is a node in a regular expression syntax tree.
+type Regexp struct {
+ Op Op // operator
+ Flags Flags
+ Sub []*Regexp // subexpressions, if any
+ Sub0 [1]*Regexp // storage for short Sub
+ Rune []int // matched runes, for OpLiteral, OpCharClass
+ Rune0 [2]int // storage for short Rune
+ Min, Max int // min, max for OpRepeat
+ Cap int // capturing index, for OpCapture
+ Name string // capturing name, for OpCapture
+}
+
+// An Op is a single regular expression operator.
+type Op uint8
+
+// Operators are listed in precedence order, tightest binding to weakest.
+
+const (
+ OpNoMatch Op = 1 + iota // matches no strings
+ OpEmptyMatch // matches empty string
+ OpLiteral // matches Runes sequence
+ OpCharClass // matches Runes interpreted as range pair list
+ OpAnyCharNotNL // matches any character
+ OpAnyChar // matches any character
+ OpBeginLine // matches empty string at beginning of line
+ OpEndLine // matches empty string at end of line
+ OpBeginText // matches empty string at beginning of text
+ OpEndText // matches empty string at end of text
+ OpWordBoundary // matches word boundary `\b`
+ OpNoWordBoundary // matches word non-boundary `\B`
+ OpCapture // capturing subexpression with index Cap, optional name Name
+ OpStar // matches Sub[0] zero or more times
+ OpPlus // matches Sub[0] one or more times
+ OpQuest // matches Sub[0] zero or one times
+ OpRepeat // matches Sub[0] at least Min times, at most Max (Max == -1 is no limit)
+ OpConcat // matches concatenation of Subs
+ OpAlternate // matches alternation of Subs
+)
+
+const opPseudo Op = 128 // where pseudo-ops start
+
+// writeRegexp writes the Perl syntax for the regular expression re to b.
+func writeRegexp(b *bytes.Buffer, re *Regexp) {
+ switch re.Op {
+ default:
+ b.WriteString("<invalid op" + strconv.Itoa(int(re.Op)) + ">")
+ case OpNoMatch:
+ b.WriteString(`[^\x00-\x{10FFFF}]`)
+ case OpEmptyMatch:
+ b.WriteString(`(?:)`)
+ case OpLiteral:
+ for _, r := range re.Rune {
+ escape(b, r, false)
+ }
+ case OpCharClass:
+ if len(re.Rune)%2 != 0 {
+ b.WriteString(`[invalid char class]`)
+ break
+ }
+ b.WriteRune('[')
+ if len(re.Rune) > 0 && re.Rune[0] == 0 && re.Rune[len(re.Rune)-1] == unicode.MaxRune {
+ // Contains 0 and MaxRune. Probably a negated class.
+ // Print the gaps.
+ b.WriteRune('^')
+ for i := 1; i < len(re.Rune)-1; i += 2 {
+ lo, hi := re.Rune[i]+1, re.Rune[i+1]-1
+ escape(b, lo, lo == '-')
+ if lo != hi {
+ b.WriteRune('-')
+ escape(b, hi, hi == '-')
+ }
+ }
+ } else {
+ for i := 0; i < len(re.Rune); i += 2 {
+ lo, hi := re.Rune[i], re.Rune[i+1]
+ escape(b, lo, lo == '-')
+ if lo != hi {
+ b.WriteRune('-')
+ escape(b, hi, hi == '-')
+ }
+ }
+ }
+ b.WriteRune(']')
+ case OpAnyCharNotNL:
+ b.WriteString(`[^\n]`)
+ case OpAnyChar:
+ b.WriteRune('.')
+ case OpBeginLine:
+ b.WriteRune('^')
+ case OpEndLine:
+ b.WriteRune('$')
+ case OpBeginText:
+ b.WriteString(`\A`)
+ case OpEndText:
+ b.WriteString(`\z`)
+ case OpWordBoundary:
+ b.WriteString(`\b`)
+ case OpNoWordBoundary:
+ b.WriteString(`\B`)
+ case OpCapture:
+ if re.Name != "" {
+ b.WriteString(`(?P<`)
+ b.WriteString(re.Name)
+ b.WriteRune('>')
+ } else {
+ b.WriteRune('(')
+ }
+ writeRegexp(b, re.Sub[0])
+ b.WriteRune(')')
+ case OpStar, OpPlus, OpQuest, OpRepeat:
+ if sub := re.Sub[0]; sub.Op > OpCapture {
+ b.WriteString(`(?:`)
+ writeRegexp(b, sub)
+ b.WriteString(`)`)
+ } else {
+ writeRegexp(b, sub)
+ }
+ switch re.Op {
+ case OpStar:
+ b.WriteRune('*')
+ case OpPlus:
+ b.WriteRune('+')
+ case OpQuest:
+ b.WriteRune('?')
+ case OpRepeat:
+ b.WriteRune('{')
+ b.WriteString(strconv.Itoa(re.Min))
+ if re.Max != re.Min {
+ b.WriteRune(',')
+ if re.Max >= 0 {
+ b.WriteString(strconv.Itoa(re.Max))
+ }
+ }
+ b.WriteRune('}')
+ }
+ case OpConcat:
+ for _, sub := range re.Sub {
+ if sub.Op == OpAlternate {
+ b.WriteString(`(?:`)
+ writeRegexp(b, sub)
+ b.WriteString(`)`)
+ } else {
+ writeRegexp(b, sub)
+ }
+ }
+ case OpAlternate:
+ for i, sub := range re.Sub {
+ if i > 0 {
+ b.WriteRune('|')
+ }
+ writeRegexp(b, sub)
+ }
+ }
+}
+
+func (re *Regexp) String() string {
+ var b bytes.Buffer
+ writeRegexp(&b, re)
+ return b.String()
+}
+
+const meta = `\.+*?()|[]{}^$`
+
+func escape(b *bytes.Buffer, r int, force bool) {
+ if unicode.IsPrint(r) {
+ if strings.IndexRune(meta, r) >= 0 || force {
+ b.WriteRune('\\')
+ }
+ b.WriteRune(r)
+ return
+ }
+
+ switch r {
+ case '\a':
+ b.WriteString(`\a`)
+ case '\f':
+ b.WriteString(`\f`)
+ case '\n':
+ b.WriteString(`\n`)
+ case '\r':
+ b.WriteString(`\r`)
+ case '\t':
+ b.WriteString(`\t`)
+ case '\v':
+ b.WriteString(`\v`)
+ default:
+ b.WriteString(`\x{`)
+ b.WriteString(strconv.Itob(r, 16))
+ b.WriteString(`}`)
+ }
+}
diff --git a/src/pkg/exp/template/Makefile b/src/pkg/exp/template/Makefile
new file mode 100644
index 000000000..ab9832f61
--- /dev/null
+++ b/src/pkg/exp/template/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=template
+GOFILES=\
+ lex.go\
+ parse.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/exp/template/lex.go b/src/pkg/exp/template/lex.go
new file mode 100644
index 000000000..826d3eb88
--- /dev/null
+++ b/src/pkg/exp/template/lex.go
@@ -0,0 +1,373 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package template
+
+import (
+ "fmt"
+ "strings"
+ "unicode"
+ "utf8"
+)
+
+// item represents a token or text string returned from the scanner.
+type item struct {
+ typ itemType
+ val string
+}
+
+func (i item) String() string {
+ switch i.typ {
+ case itemEOF:
+ return "EOF"
+ case itemError:
+ return i.val
+ }
+ if len(i.val) > 10 {
+ return fmt.Sprintf("%.10q...", i.val)
+ }
+ return fmt.Sprintf("%q", i.val)
+}
+
+// itemType identifies the type of lex item.
+type itemType int
+
+const (
+ itemError itemType = iota // error occurred; value is text of error
+ itemDot // the cursor, spelled '.'.
+ itemEOF
+ itemElse // else keyword
+ itemEnd // end keyword
+ itemField // alphanumeric identifier, starting with '.'.
+ itemIdentifier // alphanumeric identifier
+ itemIf // if keyword
+ itemLeftMeta // left meta-string
+ itemNumber // number
+ itemPipe // pipe symbol
+ itemRange // range keyword
+ itemRawString // raw quoted string (includes quotes)
+ itemRightMeta // right meta-string
+ itemString // quoted string (includes quotes)
+ itemText // plain text
+)
+
+// Make the types prettyprint.
+var itemName = map[itemType]string{
+ itemError: "error",
+ itemDot: ".",
+ itemEOF: "EOF",
+ itemElse: "else",
+ itemEnd: "end",
+ itemField: "field",
+ itemIdentifier: "identifier",
+ itemIf: "if",
+ itemLeftMeta: "left meta",
+ itemNumber: "number",
+ itemPipe: "pipe",
+ itemRange: "range",
+ itemRawString: "raw string",
+ itemRightMeta: "rightMeta",
+ itemString: "string",
+ itemText: "text",
+}
+
+func (i itemType) String() string {
+ s := itemName[i]
+ if s == "" {
+ return fmt.Sprintf("item%d", int(i))
+ }
+ return s
+}
+
+var key = map[string]itemType{
+ ".": itemDot,
+ "else": itemElse,
+ "end": itemEnd,
+ "if": itemIf,
+ "range": itemRange,
+}
+
+const eof = -1
+
+// stateFn represents the state of the scanner as a function that returns the next state.
+type stateFn func(*lexer) stateFn
+
+// lexer holds the state of the scanner.
+type lexer struct {
+ name string // the name of the input; used only for error reports.
+ input string // the string being scanned.
+ pos int // current position in the input.
+ start int // start position of this item.
+ width int // width of last rune read from input.
+ items chan item // channel of scanned items.
+}
+
+// next returns the next rune in the input.
+func (l *lexer) next() (rune int) {
+ if l.pos >= len(l.input) {
+ l.width = 0
+ return eof
+ }
+ rune, l.width = utf8.DecodeRuneInString(l.input[l.pos:])
+ l.pos += l.width
+ return rune
+}
+
+// peek returns but does not consume the next rune in the input.
+func (l *lexer) peek() int {
+ rune := l.next()
+ l.backup()
+ return rune
+}
+
+// backup steps back one rune. Can only be called once per call of next.
+func (l *lexer) backup() {
+ l.pos -= l.width
+}
+
+// emit passes an item back to the client.
+func (l *lexer) emit(t itemType) {
+ l.items <- item{t, l.input[l.start:l.pos]}
+ l.start = l.pos
+}
+
+// ignore skips over the pending input before this point.
+func (l *lexer) ignore() {
+ l.start = l.pos
+}
+
+// accept consumes the next rune if it's from the valid set.
+func (l *lexer) accept(valid string) bool {
+ if strings.IndexRune(valid, l.next()) >= 0 {
+ return true
+ }
+ l.backup()
+ return false
+}
+
+// acceptRun consumes a run of runes from the valid set.
+func (l *lexer) acceptRun(valid string) {
+ for strings.IndexRune(valid, l.next()) >= 0 {
+ }
+ l.backup()
+}
+
+// lineNumber reports which line we're on. Doing it this way
+// means we don't have to worry about peek double counting.
+func (l *lexer) lineNumber() int {
+ return 1 + strings.Count(l.input[:l.pos], "\n")
+}
+
+// error returns an error token and terminates the scan by passing
+// back a nil pointer that will be the next state, terminating l.run.
+func (l *lexer) errorf(format string, args ...interface{}) stateFn {
+ l.items <- item{itemError, fmt.Sprintf(format, args...)}
+ return nil
+}
+
+// run lexes the input by executing state functions until nil.
+func (l *lexer) run() {
+ for state := lexText; state != nil; {
+ state = state(l)
+ }
+ close(l.items)
+}
+
+// lex launches a new scanner and returns the channel of items.
+func lex(name, input string) (*lexer, chan item) {
+ l := &lexer{
+ name: name,
+ input: input,
+ items: make(chan item),
+ }
+ go l.run()
+ return l, l.items
+}
+
+// state functions
+
+const leftMeta = "{{"
+const rightMeta = "}}"
+
+// lexText scans until a metacharacter
+func lexText(l *lexer) stateFn {
+ for {
+ if strings.HasPrefix(l.input[l.pos:], leftMeta) {
+ if l.pos > l.start {
+ l.emit(itemText)
+ }
+ return lexLeftMeta
+ }
+ if l.next() == eof {
+ break
+ }
+ }
+ // Correctly reached EOF.
+ if l.pos > l.start {
+ l.emit(itemText)
+ }
+ l.emit(itemEOF)
+ return nil
+}
+
+// leftMeta scans the left "metacharacter", which is known to be present.
+func lexLeftMeta(l *lexer) stateFn {
+ l.pos += len(leftMeta)
+ l.emit(itemLeftMeta)
+ return lexInsideAction
+}
+
+// rightMeta scans the right "metacharacter", which is known to be present.
+func lexRightMeta(l *lexer) stateFn {
+ l.pos += len(rightMeta)
+ l.emit(itemRightMeta)
+ return lexText
+}
+
+// lexInsideAction scans the elements inside "metacharacters".
+func lexInsideAction(l *lexer) stateFn {
+ // Either number, quoted string, or identifier.
+ // Spaces separate and are ignored.
+ // Pipe symbols separate and are emitted.
+ for {
+ if strings.HasPrefix(l.input[l.pos:], rightMeta) {
+ return lexRightMeta
+ }
+ switch r := l.next(); {
+ case r == eof || r == '\n':
+ return l.errorf("unclosed action")
+ case isSpace(r):
+ l.ignore()
+ case r == '|':
+ l.emit(itemPipe)
+ case r == '"':
+ return lexQuote
+ case r == '`':
+ return lexRawQuote
+ case r == '.':
+ // special look-ahead for ".field" so we don't break l.backup().
+ if l.pos < len(l.input) {
+ r := l.input[l.pos]
+ if r < '0' || '9' < r {
+ return lexIdentifier // itemDot comes from the keyword table.
+ }
+ }
+ fallthrough // '.' can start a number.
+ case r == '+' || r == '-' || ('0' <= r && r <= '9'):
+ l.backup()
+ return lexNumber
+ case isAlphaNumeric(r):
+ l.backup()
+ return lexIdentifier
+ default:
+ return l.errorf("unrecognized character in action: %#U", r)
+ }
+ }
+ return nil
+}
+
+// lexIdentifier scans an alphanumeric or field.
+func lexIdentifier(l *lexer) stateFn {
+Loop:
+ for {
+ switch r := l.next(); {
+ case isAlphaNumeric(r):
+ // absorb
+ default:
+ l.backup()
+ word := l.input[l.start:l.pos]
+ switch {
+ case key[word] != itemError:
+ l.emit(key[word])
+ case word[0] == '.':
+ l.emit(itemField)
+ default:
+ l.emit(itemIdentifier)
+ }
+ break Loop
+ }
+ }
+ return lexInsideAction
+}
+
+// lexNumber scans a number: decimal, octal, hex, float, or imaginary. This
+// isn't a perfect number scanner - for instance it accepts "." and "0x0.2"
+// and "089" - but when it's wrong the input is invalid and the parser (via
+// strconv) will notice.
+// TODO: without expressions you can do imaginary but not complex.
+func lexNumber(l *lexer) stateFn {
+ // Optional leading sign.
+ l.accept("+-")
+ // Is it hex?
+ digits := "0123456789"
+ if l.accept("0") && l.accept("xX") {
+ digits = "0123456789abcdefABCDEF"
+ }
+ l.acceptRun(digits)
+ if l.accept(".") {
+ l.acceptRun(digits)
+ }
+ if l.accept("eE") {
+ l.accept("+-")
+ l.acceptRun("0123456789")
+ }
+ // Is it imaginary?
+ l.accept("i")
+ // Next thing mustn't be alphanumeric.
+ if isAlphaNumeric(l.peek()) {
+ l.next()
+ return l.errorf("bad number syntax: %q", l.input[l.start:l.pos])
+ }
+ l.emit(itemNumber)
+ return lexInsideAction
+}
+
+// lexQuote scans a quoted string.
+func lexQuote(l *lexer) stateFn {
+Loop:
+ for {
+ switch l.next() {
+ case '\\':
+ if r := l.next(); r != eof && r != '\n' {
+ break
+ }
+ fallthrough
+ case eof, '\n':
+ return l.errorf("unterminated quoted string")
+ case '"':
+ break Loop
+ }
+ }
+ l.emit(itemString)
+ return lexInsideAction
+}
+
+// lexRawQuote scans a raw quoted string.
+func lexRawQuote(l *lexer) stateFn {
+Loop:
+ for {
+ switch l.next() {
+ case eof, '\n':
+ return l.errorf("unterminated raw quoted string")
+ case '`':
+ break Loop
+ }
+ }
+ l.emit(itemRawString)
+ return lexInsideAction
+}
+
+// isSpace reports whether r is a space character.
+func isSpace(r int) bool {
+ switch r {
+ case ' ', '\t', '\n', '\r':
+ return true
+ }
+ return false
+}
+
+// isAlphaNumeric reports whether r is an alphabetic, digit, or underscore.
+func isAlphaNumeric(r int) bool {
+ return r == '_' || unicode.IsLetter(r) || unicode.IsDigit(r)
+}
diff --git a/src/pkg/exp/template/lex_test.go b/src/pkg/exp/template/lex_test.go
new file mode 100644
index 000000000..184e833ef
--- /dev/null
+++ b/src/pkg/exp/template/lex_test.go
@@ -0,0 +1,129 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package template
+
+import (
+ "reflect"
+ "testing"
+)
+
+type lexTest struct {
+ name string
+ input string
+ items []item
+}
+
+var (
+ tEOF = item{itemEOF, ""}
+ tLeft = item{itemLeftMeta, "{{"}
+ tRight = item{itemRightMeta, "}}"}
+ tRange = item{itemRange, "range"}
+ tPipe = item{itemPipe, "|"}
+ tFor = item{itemIdentifier, "for"}
+ tQuote = item{itemString, `"abc \n\t\" "`}
+ raw = "`" + `abc\n\t\" ` + "`"
+ tRawQuote = item{itemRawString, raw}
+)
+
+var lexTests = []lexTest{
+ {"empty", "", []item{tEOF}},
+ {"spaces", " \t\n", []item{{itemText, " \t\n"}, tEOF}},
+ {"text", `now is the time`, []item{{itemText, "now is the time"}, tEOF}},
+ {"empty action", `{{}}`, []item{tLeft, tRight, tEOF}},
+ {"for", `{{for }}`, []item{tLeft, tFor, tRight, tEOF}},
+ {"quote", `{{"abc \n\t\" "}}`, []item{tLeft, tQuote, tRight, tEOF}},
+ {"raw quote", "{{" + raw + "}}", []item{tLeft, tRawQuote, tRight, tEOF}},
+ {"numbers", "{{1 02 0x14 -7.2i 1e3 +1.2e-4}}", []item{
+ tLeft,
+ {itemNumber, "1"},
+ {itemNumber, "02"},
+ {itemNumber, "0x14"},
+ {itemNumber, "-7.2i"},
+ {itemNumber, "1e3"},
+ {itemNumber, "+1.2e-4"},
+ tRight,
+ tEOF,
+ }},
+ {"dots", "{{.x . .2 .x.y }}", []item{
+ tLeft,
+ {itemField, ".x"},
+ {itemDot, "."},
+ {itemNumber, ".2"},
+ {itemField, ".x"},
+ {itemField, ".y"},
+ tRight,
+ tEOF,
+ }},
+ {"keywords", "{{range if else end}}", []item{
+ tLeft,
+ {itemRange, "range"},
+ {itemIf, "if"},
+ {itemElse, "else"},
+ {itemEnd, "end"},
+ tRight,
+ tEOF,
+ }},
+ {"pipeline", `intro {{echo hi 1.2 |noargs|args 1 "hi"}} outro`, []item{
+ {itemText, "intro "},
+ tLeft,
+ {itemIdentifier, "echo"},
+ {itemIdentifier, "hi"},
+ {itemNumber, "1.2"},
+ tPipe,
+ {itemIdentifier, "noargs"},
+ tPipe,
+ {itemIdentifier, "args"},
+ {itemNumber, "1"},
+ {itemString, `"hi"`},
+ tRight,
+ {itemText, " outro"},
+ tEOF,
+ }},
+ // errors
+ {"badchar", "#{{#}}", []item{
+ {itemText, "#"},
+ tLeft,
+ {itemError, "unrecognized character in action: U+0023 '#'"},
+ }},
+ {"unclosed action", "{{\n}}", []item{
+ tLeft,
+ {itemError, "unclosed action"},
+ }},
+ {"EOF in action", "{{range", []item{
+ tLeft,
+ tRange,
+ {itemError, "unclosed action"},
+ }},
+ {"unclosed quote", "{{\"\n\"}}", []item{
+ tLeft,
+ {itemError, "unterminated quoted string"},
+ }},
+ {"unclosed raw quote", "{{`xx\n`}}", []item{
+ tLeft,
+ {itemError, "unterminated raw quoted string"},
+ }},
+ {"bad number", "{{3k}}", []item{
+ tLeft,
+ {itemError, `bad number syntax: "3k"`},
+ }},
+}
+
+// collect gathers the emitted items into a slice.
+func collect(t *lexTest) (items []item) {
+ _, tokens := lex(t.name, t.input)
+ for i := range tokens {
+ items = append(items, i)
+ }
+ return
+}
+
+func TestLex(t *testing.T) {
+ for _, test := range lexTests {
+ items := collect(&test)
+ if !reflect.DeepEqual(items, test.items) {
+ t.Errorf("%s: got\n\t%v\nexpected\n\t%v", test.name, items, test.items)
+ }
+ }
+}
diff --git a/src/pkg/exp/template/parse.go b/src/pkg/exp/template/parse.go
new file mode 100644
index 000000000..57ddb0084
--- /dev/null
+++ b/src/pkg/exp/template/parse.go
@@ -0,0 +1,522 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package template
+
+import (
+ "bytes"
+ "fmt"
+ "os"
+ "runtime"
+ "strconv"
+)
+
+// Template is the representation of a parsed template.
+type Template struct {
+ // TODO: At the moment, these are all internal to parsing.
+ name string
+ root *listNode
+ lex *lexer
+ tokens chan item
+ token item // token lookahead for parser
+ havePeek bool
+}
+
+// next returns the next token.
+func (t *Template) next() item {
+ if t.havePeek {
+ t.havePeek = false
+ } else {
+ t.token = <-t.tokens
+ }
+ return t.token
+}
+
+// backup backs the input stream up one token.
+func (t *Template) backup() {
+ t.havePeek = true
+}
+
+// peek returns but does not consume the next token.
+func (t *Template) peek() item {
+ if t.havePeek {
+ return t.token
+ }
+ t.token = <-t.tokens
+ t.havePeek = true
+ return t.token
+}
+
+// A node is an element in the parse tree. The interface is trivial.
+type node interface {
+ typ() nodeType
+ String() string
+}
+
+type nodeType int
+
+func (t nodeType) typ() nodeType {
+ return t
+}
+
+const (
+ nodeText nodeType = iota
+ nodeAction
+ nodeCommand
+ nodeElse
+ nodeEnd
+ nodeField
+ nodeIdentifier
+ nodeList
+ nodeNumber
+ nodeRange
+ nodeString
+)
+
+// Nodes.
+
+// listNode holds a sequence of nodes.
+type listNode struct {
+ nodeType
+ nodes []node
+}
+
+func newList() *listNode {
+ return &listNode{nodeType: nodeList}
+}
+
+func (l *listNode) append(n node) {
+ l.nodes = append(l.nodes, n)
+}
+
+func (l *listNode) String() string {
+ b := new(bytes.Buffer)
+ fmt.Fprint(b, "[")
+ for _, n := range l.nodes {
+ fmt.Fprint(b, n)
+ }
+ fmt.Fprint(b, "]")
+ return b.String()
+}
+
+// textNode holds plain text.
+type textNode struct {
+ nodeType
+ text string
+}
+
+func newText(text string) *textNode {
+ return &textNode{nodeType: nodeText, text: text}
+}
+
+func (t *textNode) String() string {
+ return fmt.Sprintf("(text: %q)", t.text)
+}
+
+// actionNode holds an action (something bounded by metacharacters).
+type actionNode struct {
+ nodeType
+ pipeline []*commandNode
+}
+
+func newAction() *actionNode {
+ return &actionNode{nodeType: nodeAction}
+}
+
+func (a *actionNode) append(command *commandNode) {
+ a.pipeline = append(a.pipeline, command)
+}
+
+func (a *actionNode) String() string {
+ return fmt.Sprintf("(action: %v)", a.pipeline)
+}
+
+// commandNode holds a command (a pipeline inside an evaluating action).
+type commandNode struct {
+ nodeType
+ args []node // identifier, string, or number
+}
+
+func newCommand() *commandNode {
+ return &commandNode{nodeType: nodeCommand}
+}
+
+func (c *commandNode) append(arg node) {
+ c.args = append(c.args, arg)
+}
+
+func (c *commandNode) String() string {
+ return fmt.Sprintf("(command: %v)", c.args)
+}
+
+// identifierNode holds an identifier.
+type identifierNode struct {
+ nodeType
+ ident string
+}
+
+func newIdentifier(ident string) *identifierNode {
+ return &identifierNode{nodeType: nodeIdentifier, ident: ident}
+}
+
+func (i *identifierNode) String() string {
+ return fmt.Sprintf("I=%s", i.ident)
+}
+
+// fieldNode holds a field (identifier starting with '.'). The period is dropped from the ident.
+type fieldNode struct {
+ nodeType
+ ident string
+}
+
+func newField(ident string) *fieldNode {
+ return &fieldNode{nodeType: nodeField, ident: ident[1:]} //drop period
+}
+
+func (f *fieldNode) String() string {
+ return fmt.Sprintf("F=.%s", f.ident)
+}
+
+// numberNode holds a number, signed or unsigned, integer, floating, or imaginary.
+// The value is parsed and stored under all the types that can represent the value.
+// This simulates in a small amount of code the behavior of Go's ideal constants.
+// TODO: booleans, complex numbers.
+type numberNode struct {
+ nodeType
+ isInt bool // number has an integral value
+ isUint bool // number has an unsigned integral value
+ isFloat bool // number has a floating-point value
+ imaginary bool // number is imaginary
+ int64 // the signed integer value
+ uint64 // the unsigned integer value
+ float64 // the positive floating-point value
+ text string
+}
+
+func newNumber(text string) (*numberNode, os.Error) {
+ n := &numberNode{nodeType: nodeNumber, text: text}
+ // Imaginary constants can only be floating-point.
+ if len(text) > 0 && text[len(text)-1] == 'i' {
+ f, err := strconv.Atof64(text[:len(text)-1])
+ if err == nil {
+ n.imaginary = true
+ n.isFloat = true
+ n.float64 = f
+ return n, nil
+ }
+ }
+ // Do integer test first so we get 0x123 etc.
+ u, err := strconv.Btoui64(text, 0) // will fail for -0; fixed below.
+ if err == nil {
+ n.isUint = true
+ n.uint64 = u
+ }
+ i, err := strconv.Btoi64(text, 0)
+ if err == nil {
+ n.isInt = true
+ n.int64 = i
+ if i == 0 {
+ n.isUint = true // in case of -0.
+ n.uint64 = u
+ }
+ }
+ // If an integer extraction succeeded, promote the float.
+ if n.isInt {
+ n.isFloat = true
+ n.float64 = float64(n.int64)
+ } else if n.isUint {
+ n.isFloat = true
+ n.float64 = float64(n.uint64)
+ } else {
+ f, err := strconv.Atof64(text)
+ if err == nil {
+ n.isFloat = true
+ n.float64 = f
+ // If a floating-point extraction succeeded, extract the int if needed.
+ if !n.isInt && float64(int64(f)) == f {
+ n.isInt = true
+ n.int64 = int64(f)
+ }
+ if !n.isUint && float64(uint64(f)) == f {
+ n.isUint = true
+ n.uint64 = uint64(f)
+ }
+ }
+ }
+ if !n.isInt && !n.isUint && !n.isFloat {
+ return nil, fmt.Errorf("illegal number syntax: %q", text)
+ }
+ return n, nil
+}
+
+func (n *numberNode) String() string {
+ return fmt.Sprintf("N=%s", n.text)
+}
+
+// stringNode holds a quoted string.
+type stringNode struct {
+ nodeType
+ text string
+}
+
+func newString(text string) *stringNode {
+ return &stringNode{nodeType: nodeString, text: text}
+}
+
+func (s *stringNode) String() string {
+ return fmt.Sprintf("S=%#q", s.text)
+}
+
+// endNode represents an {{end}} action. It is represented by a nil pointer.
+type endNode bool
+
+func newEnd() *endNode {
+ return nil
+}
+
+func (e *endNode) typ() nodeType {
+ return nodeEnd
+}
+
+func (e *endNode) String() string {
+ return "{{end}}"
+}
+
+// elseNode represents an {{else}} action. It is represented by a nil pointer.
+type elseNode bool
+
+func newElse() *elseNode {
+ return nil
+}
+
+func (e *elseNode) typ() nodeType {
+ return nodeElse
+}
+
+func (e *elseNode) String() string {
+ return "{{else}}"
+}
+
+// rangeNode represents an {{range}} action and its commands.
+type rangeNode struct {
+ nodeType
+ field node
+ list *listNode
+ elseList *listNode
+}
+
+func newRange(field node, list *listNode) *rangeNode {
+ return &rangeNode{nodeType: nodeRange, field: field, list: list}
+}
+
+func (r *rangeNode) String() string {
+ if r.elseList != nil {
+ return fmt.Sprintf("({{range %s}} %s {{else}} %s)", r.field, r.list, r.elseList)
+ }
+ return fmt.Sprintf("({{range %s}} %s)", r.field, r.list)
+}
+
+// Parsing.
+
+// New allocates a new template with the given name.
+func New(name string) *Template {
+ return &Template{
+ name: name,
+ }
+}
+
+// errorf formats the error and terminates processing.
+func (t *Template) errorf(format string, args ...interface{}) {
+ format = fmt.Sprintf("template: %s:%d: %s", t.name, t.lex.lineNumber(), format)
+ panic(fmt.Errorf(format, args...))
+}
+
+// error terminates processing.
+func (t *Template) error(err os.Error) {
+ t.errorf("%s", err)
+}
+
+// expect consumes the next token and guarantees it has the required type.
+func (t *Template) expect(expected itemType, context string) item {
+ token := t.next()
+ if token.typ != expected {
+ t.errorf("expected %s in %s; got %s", expected, context, token)
+ }
+ return token
+}
+
+// unexpected complains about the token and terminates processing.
+func (t *Template) unexpected(token item, context string) {
+ t.errorf("unexpected %s in %s", token, context)
+}
+
+// Parse parses the template definition string and constructs an efficient representation of the template.
+func (t *Template) Parse(s string) (err os.Error) {
+ t.lex, t.tokens = lex(t.name, s)
+ defer func() {
+ e := recover()
+ if e != nil {
+ if _, ok := e.(runtime.Error); ok {
+ panic(e)
+ }
+ err = e.(os.Error)
+ }
+ return
+ }()
+ var next node
+ t.root, next = t.itemList(true)
+ if next != nil {
+ t.errorf("unexpected %s", next)
+ }
+ return nil
+}
+
+// itemList:
+// textOrAction*
+// Terminates at EOF and at {{end}} or {{else}}, which is returned separately.
+// The toEOF flag tells whether we expect to reach EOF.
+func (t *Template) itemList(toEOF bool) (list *listNode, next node) {
+ list = newList()
+ for t.peek().typ != itemEOF {
+ n := t.textOrAction()
+ switch n.typ() {
+ case nodeEnd, nodeElse:
+ return list, n
+ }
+ list.append(n)
+ }
+ if !toEOF {
+ t.unexpected(t.next(), "input")
+ }
+ return list, nil
+}
+
+// textOrAction:
+// text | action
+func (t *Template) textOrAction() node {
+ switch token := t.next(); token.typ {
+ case itemText:
+ return newText(token.val)
+ case itemLeftMeta:
+ return t.action()
+ default:
+ t.unexpected(token, "input")
+ }
+ return nil
+}
+
+// Action:
+// control
+// command ("|" command)*
+// Left meta is past. Now get actions.
+func (t *Template) action() (n node) {
+ action := newAction()
+ switch token := t.next(); token.typ {
+ case itemRange:
+ return t.rangeControl()
+ case itemElse:
+ return t.elseControl()
+ case itemEnd:
+ return t.endControl()
+ }
+ t.backup()
+Loop:
+ for {
+ switch token := t.next(); token.typ {
+ case itemRightMeta:
+ break Loop
+ case itemIdentifier, itemField:
+ t.backup()
+ cmd, err := t.command()
+ if err != nil {
+ t.error(err)
+ }
+ action.append(cmd)
+ default:
+ t.unexpected(token, "command")
+ }
+ }
+ return action
+}
+
+// Range:
+// {{range field}} itemList {{end}}
+// {{range field}} itemList {{else}} itemList {{end}}
+// Range keyword is past.
+func (t *Template) rangeControl() node {
+ field := t.expect(itemField, "range")
+ t.expect(itemRightMeta, "range")
+ list, next := t.itemList(false)
+ r := newRange(newField(field.val), list)
+ switch next.typ() {
+ case nodeEnd: //done
+ case nodeElse:
+ elseList, next := t.itemList(false)
+ if next.typ() != nodeEnd {
+ t.errorf("expected end; found %s", next)
+ }
+ r.elseList = elseList
+ }
+ return r
+}
+
+// End:
+// {{end}}
+// End keyword is past.
+func (t *Template) endControl() node {
+ t.expect(itemRightMeta, "end")
+ return newEnd()
+}
+
+// Else:
+// {{else}}
+// Else keyword is past.
+func (t *Template) elseControl() node {
+ t.expect(itemRightMeta, "else")
+ return newElse()
+}
+
+// command:
+// space-separated arguments up to a pipeline character or right metacharacter.
+// we consume the pipe character but leave the right meta to terminate the action.
+func (t *Template) command() (*commandNode, os.Error) {
+ cmd := newCommand()
+Loop:
+ for {
+ switch token := t.next(); token.typ {
+ case itemRightMeta:
+ t.backup()
+ break Loop
+ case itemPipe:
+ break Loop
+ case itemError:
+ return nil, os.NewError(token.val)
+ case itemIdentifier:
+ cmd.append(newIdentifier(token.val))
+ case itemField:
+ cmd.append(newField(token.val))
+ case itemNumber:
+ if len(cmd.args) == 0 {
+ t.errorf("command cannot be %q", token.val)
+ }
+ number, err := newNumber(token.val)
+ if err != nil {
+ t.error(err)
+ }
+ cmd.append(number)
+ case itemString, itemRawString:
+ if len(cmd.args) == 0 {
+ t.errorf("command cannot be %q", token.val)
+ }
+ s, err := strconv.Unquote(token.val)
+ if err != nil {
+ return nil, err
+ }
+ cmd.append(newString(s))
+ default:
+ t.unexpected(token, "command")
+ }
+ }
+ return cmd, nil
+}
diff --git a/src/pkg/exp/template/parse_test.go b/src/pkg/exp/template/parse_test.go
new file mode 100644
index 000000000..f89eaa6ce
--- /dev/null
+++ b/src/pkg/exp/template/parse_test.go
@@ -0,0 +1,176 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package template
+
+import (
+ "fmt"
+ "testing"
+)
+
+const dumpErrors = true
+
+type numberTest struct {
+ text string
+ isInt bool
+ isUint bool
+ isFloat bool
+ imaginary bool
+ int64
+ uint64
+ float64
+}
+
+var numberTests = []numberTest{
+ // basics
+ {"0", true, true, true, false, 0, 0, 0},
+ {"-0", true, true, true, false, 0, 0, 0}, // check that -0 is a uint.
+ {"73", true, true, true, false, 73, 73, 73},
+ {"-73", true, false, true, false, -73, 0, -73},
+ {"+73", true, false, true, false, 73, 0, 73},
+ {"100", true, true, true, false, 100, 100, 100},
+ {"1e9", true, true, true, false, 1e9, 1e9, 1e9},
+ {"-1e9", true, false, true, false, -1e9, 0, -1e9},
+ {"-1.2", false, false, true, false, 0, 0, -1.2},
+ {"1e19", false, true, true, false, 0, 1e19, 1e19},
+ {"-1e19", false, false, true, false, 0, 0, -1e19},
+ {"4i", false, false, true, true, 0, 0, 4},
+ // funny bases
+ {"0123", true, true, true, false, 0123, 0123, 0123},
+ {"-0x0", true, true, true, false, 0, 0, 0},
+ {"0xdeadbeef", true, true, true, false, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef},
+ // some broken syntax
+ {text: "+-2"},
+ {text: "0x123."},
+ {text: "1e."},
+ {text: "0xi."},
+}
+
+func TestNumberParse(t *testing.T) {
+ for _, test := range numberTests {
+ n, err := newNumber(test.text)
+ ok := test.isInt || test.isUint || test.isFloat
+ if ok && err != nil {
+ t.Errorf("unexpected error for %q", test.text)
+ continue
+ }
+ if !ok && err == nil {
+ t.Errorf("expected error for %q", test.text)
+ continue
+ }
+ if !ok {
+ continue
+ }
+ if n.imaginary != test.imaginary {
+ t.Errorf("imaginary incorrect for %q; should be %t", test.text, test.imaginary)
+ }
+ if test.isInt {
+ if !n.isInt {
+ t.Errorf("expected integer for %q", test.text)
+ }
+ if n.int64 != test.int64 {
+ t.Errorf("int64 for %q should be %d is %d", test.text, test.int64, n.int64)
+ }
+ } else if n.isInt {
+ t.Errorf("did not expect integer for %q", test.text)
+ }
+ if test.isUint {
+ if !n.isUint {
+ t.Errorf("expected unsigned integer for %q", test.text)
+ }
+ if n.uint64 != test.uint64 {
+ t.Errorf("uint64 for %q should be %d is %d", test.text, test.uint64, n.uint64)
+ }
+ } else if n.isUint {
+ t.Errorf("did not expect unsigned integer for %q", test.text)
+ }
+ if test.isFloat {
+ if !n.isFloat {
+ t.Errorf("expected float for %q", test.text)
+ }
+ if n.float64 != test.float64 {
+ t.Errorf("float64 for %q should be %g is %g", test.text, test.float64, n.float64)
+ }
+ } else if n.isFloat {
+ t.Errorf("did not expect float for %q", test.text)
+ }
+ }
+}
+
+func num(s string) *numberNode {
+ n, err := newNumber(s)
+ if err != nil {
+ panic(err)
+ }
+ return n
+}
+
+type parseTest struct {
+ name string
+ input string
+ ok bool
+ result string
+}
+
+const (
+ noError = true
+ hasError = false
+)
+
+var parseTests = []parseTest{
+ {"empty", "", noError,
+ `[]`},
+ {"spaces", " \t\n", noError,
+ `[(text: " \t\n")]`},
+ {"text", "some text", noError,
+ `[(text: "some text")]`},
+ {"emptyMeta", "{{}}", noError,
+ `[(action: [])]`},
+ {"simple command", "{{hello}}", noError,
+ `[(action: [(command: [I=hello])])]`},
+ {"multi-word command", "{{hello world}}", noError,
+ `[(action: [(command: [I=hello I=world])])]`},
+ {"multi-word command with number", "{{hello 80}}", noError,
+ `[(action: [(command: [I=hello N=80])])]`},
+ {"multi-word command with string", "{{hello `quoted text`}}", noError,
+ "[(action: [(command: [I=hello S=`quoted text`])])]"},
+ {"pipeline", "{{hello|world}}", noError,
+ `[(action: [(command: [I=hello]) (command: [I=world])])]`},
+ {"simple range", "{{range .x}}hello{{end}}", noError,
+ `[({{range F=.x}} [(text: "hello")])]`},
+ {"nested range", "{{range .x}}hello{{range .y}}goodbye{{end}}{{end}}", noError,
+ `[({{range F=.x}} [(text: "hello")({{range F=.y}} [(text: "goodbye")])])]`},
+ {"range with else", "{{range .x}}true{{else}}false{{end}}", noError,
+ `[({{range F=.x}} [(text: "true")] {{else}} [(text: "false")])]`},
+ // Errors.
+ {"unclosed action", "hello{{range", hasError, ""},
+ {"not a field", "hello{{range x}}{{end}}", hasError, ""},
+ {"missing end", "hello{{range .x}}", hasError, ""},
+ {"missing end after else", "hello{{range .x}}{{else}}", hasError, ""},
+}
+
+func TestParse(t *testing.T) {
+ for _, test := range parseTests {
+ tmpl := New(test.name)
+ err := tmpl.Parse(test.input)
+ switch {
+ case err == nil && !test.ok:
+ t.Errorf("%q: expected error; got none", test.name)
+ continue
+ case err != nil && test.ok:
+ t.Errorf("%q: unexpected error: %v", test.name, err)
+ continue
+ case err != nil && !test.ok:
+ // expected error, got one
+ if dumpErrors {
+ fmt.Printf("%s: %s\n\t%s\n", test.name, test.input, err)
+ }
+ continue
+ }
+ result := tmpl.root.String()
+ if result != test.result {
+ t.Errorf("%s=(%q): got\n\t%v\nexpected\n\t%v", test.name, test.input, result, test.result)
+ }
+ }
+}
diff --git a/src/pkg/flag/flag.go b/src/pkg/flag/flag.go
index e5d2f94e9..f9b852c0f 100644
--- a/src/pkg/flag/flag.go
+++ b/src/pkg/flag/flag.go
@@ -218,7 +218,7 @@ type Flag struct {
// sortFlags returns the flags as a slice in lexicographical sorted order.
func sortFlags(flags map[string]*Flag) []*Flag {
- list := make(sort.StringArray, len(flags))
+ list := make(sort.StringSlice, len(flags))
i := 0
for _, f := range flags {
list[i] = f.Name
diff --git a/src/pkg/fmt/doc.go b/src/pkg/fmt/doc.go
index 79fe5758c..35a11e19f 100644
--- a/src/pkg/fmt/doc.go
+++ b/src/pkg/fmt/doc.go
@@ -63,11 +63,13 @@
number of characters to output, truncating if necessary.
Other flags:
- + always print a sign for numeric values
+ + always print a sign for numeric values;
+ guarantee ASCII-only output for %q (%+q)
- pad with spaces on the right rather than the left (left-justify the field)
# alternate format: add leading 0 for octal (%#o), 0x for hex (%#x);
0X for hex (%#X); suppress 0x for %p (%#p);
- print a raw (backquoted) string if possible for %q (%#q)
+ print a raw (backquoted) string if possible for %q (%#q);
+ write e.g. U+0078 'x' if the character is printable for %U (%#U).
' ' (space) leave a space for elided sign in numbers (% d);
put spaces between bytes printing strings or slices in hex (% x, % X)
0 pad with leading zeros rather than spaces
diff --git a/src/pkg/fmt/fmt_test.go b/src/pkg/fmt/fmt_test.go
index 122b9516b..9a8024528 100644
--- a/src/pkg/fmt/fmt_test.go
+++ b/src/pkg/fmt/fmt_test.go
@@ -133,6 +133,7 @@ var fmttests = []struct {
{"%q", "\a\b\f\r\n\t\v", `"\a\b\f\r\n\t\v"`},
{"%q", "abc\xffdef", `"abc\xffdef"`},
{"%q", "\u263a", `"☺"`},
+ {"%+q", "\u263a", `"\u263a"`},
{"%q", "\U0010ffff", `"\U0010ffff"`},
// escaped characters
@@ -145,6 +146,8 @@ var fmttests = []struct {
{"%q", uint64(0xFFFFFFFF), `%!q(uint64=4294967295)`},
{"%q", '"', `'"'`},
{"%q", '\'', `'\''`},
+ {"%q", "\u263a", `"☺"`},
+ {"%+q", "\u263a", `"\u263a"`},
// width
{"%5s", "abc", " abc"},
@@ -187,6 +190,12 @@ var fmttests = []struct {
{"%U", 0x12345, "U+12345"},
{"%10.6U", 0xABC, " U+000ABC"},
{"%-10.6U", 0xABC, "U+000ABC "},
+ {"%U", '\n', `U+000A`},
+ {"%#U", '\n', `U+000A`},
+ {"%U", 'x', `U+0078`},
+ {"%#U", 'x', `U+0078 'x'`},
+ {"%U", '\u263a', `U+263A`},
+ {"%#U", '\u263a', `U+263A '☺'`},
// floats
{"%+.3e", 0.0, "+0.000e+00"},
@@ -674,3 +683,56 @@ func TestWidthAndPrecision(t *testing.T) {
}
}
}
+
+// A type that panics in String.
+type Panic struct {
+ message interface{}
+}
+
+// Value receiver.
+func (p Panic) GoString() string {
+ panic(p.message)
+}
+
+// Value receiver.
+func (p Panic) String() string {
+ panic(p.message)
+}
+
+// A type that panics in Format.
+type PanicF struct {
+ message interface{}
+}
+
+// Value receiver.
+func (p PanicF) Format(f State, c int) {
+ panic(p.message)
+}
+
+var panictests = []struct {
+ fmt string
+ in interface{}
+ out string
+}{
+ // String
+ {"%d", (*Panic)(nil), "<nil>"}, // nil pointer special case
+ {"%d", Panic{io.ErrUnexpectedEOF}, "%d(PANIC=unexpected EOF)"},
+ {"%d", Panic{3}, "%d(PANIC=3)"},
+ // GoString
+ {"%#v", (*Panic)(nil), "<nil>"}, // nil pointer special case
+ {"%#v", Panic{io.ErrUnexpectedEOF}, "%v(PANIC=unexpected EOF)"},
+ {"%#v", Panic{3}, "%v(PANIC=3)"},
+ // Format
+ {"%s", (*PanicF)(nil), "<nil>"}, // nil pointer special case
+ {"%s", PanicF{io.ErrUnexpectedEOF}, "%s(PANIC=unexpected EOF)"},
+ {"%s", PanicF{3}, "%s(PANIC=3)"},
+}
+
+func TestPanics(t *testing.T) {
+ for _, tt := range panictests {
+ s := Sprintf(tt.fmt, tt.in)
+ if s != tt.out {
+ t.Errorf("%q: got %q expected %q", tt.fmt, s, tt.out)
+ }
+ }
+}
diff --git a/src/pkg/fmt/format.go b/src/pkg/fmt/format.go
index 5dcfb9677..bec55f75b 100644
--- a/src/pkg/fmt/format.go
+++ b/src/pkg/fmt/format.go
@@ -7,6 +7,7 @@ package fmt
import (
"bytes"
"strconv"
+ "unicode"
"utf8"
)
@@ -50,6 +51,7 @@ type fmt struct {
sharp bool
space bool
unicode bool
+ uniQuote bool // Use 'x'= prefix for %U if printable.
zero bool
}
@@ -63,6 +65,7 @@ func (f *fmt) clearflags() {
f.sharp = false
f.space = false
f.unicode = false
+ f.uniQuote = false
f.zero = false
}
@@ -232,6 +235,24 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
i--
buf[i] = ' '
}
+
+ // If we want a quoted char for %#U, move the data up to make room.
+ if f.unicode && f.uniQuote && a >= 0 && a <= unicode.MaxRune && unicode.IsPrint(int(a)) {
+ runeWidth := utf8.RuneLen(int(a))
+ width := 1 + 1 + runeWidth + 1 // space, quote, rune, quote
+ copy(buf[i-width:], buf[i:]) // guaranteed to have enough room.
+ i -= width
+ // Now put " 'x'" at the end.
+ j := len(buf) - width
+ buf[j] = ' '
+ j++
+ buf[j] = '\''
+ j++
+ utf8.EncodeRune(buf[j:], int(a))
+ j += runeWidth
+ buf[j] = '\''
+ }
+
f.pad(buf[i:])
}
@@ -291,7 +312,11 @@ func (f *fmt) fmt_q(s string) {
if f.sharp && strconv.CanBackquote(s) {
quoted = "`" + s + "`"
} else {
- quoted = strconv.Quote(s)
+ if f.plus {
+ quoted = strconv.QuoteToASCII(s)
+ } else {
+ quoted = strconv.Quote(s)
+ }
}
f.padString(quoted)
}
@@ -299,7 +324,12 @@ func (f *fmt) fmt_q(s string) {
// fmt_qc formats the integer as a single-quoted, escaped Go character constant.
// If the character is not valid Unicode, it will print '\ufffd'.
func (f *fmt) fmt_qc(c int64) {
- quoted := strconv.QuoteRune(int(c))
+ var quoted string
+ if f.plus {
+ quoted = strconv.QuoteRuneToASCII(int(c))
+ } else {
+ quoted = strconv.QuoteRune(int(c))
+ }
f.padString(quoted)
}
diff --git a/src/pkg/fmt/print.go b/src/pkg/fmt/print.go
index c18a8ea38..438e0ae26 100644
--- a/src/pkg/fmt/print.go
+++ b/src/pkg/fmt/print.go
@@ -22,6 +22,7 @@ var (
nilBytes = []byte("nil")
mapBytes = []byte("map[")
missingBytes = []byte("(MISSING)")
+ panicBytes = []byte("(PANIC=")
extraBytes = []byte("%!(EXTRA ")
irparenBytes = []byte("i)")
bytesBytes = []byte("[]byte{")
@@ -69,10 +70,11 @@ type GoStringer interface {
}
type pp struct {
- n int
- buf bytes.Buffer
- runeBuf [utf8.UTFMax]byte
- fmt fmt
+ n int
+ panicking bool
+ buf bytes.Buffer
+ runeBuf [utf8.UTFMax]byte
+ fmt fmt
}
// A cache holds a set of reusable objects.
@@ -111,6 +113,7 @@ var ppFree = newCache(func() interface{} { return new(pp) })
// Allocate a new pp struct or grab a cached one.
func newPrinter() *pp {
p := ppFree.get().(*pp)
+ p.panicking = false
p.fmt.init(&p.buf)
return p
}
@@ -186,7 +189,7 @@ func Sprintf(format string, a ...interface{}) string {
// Errorf formats according to a format specifier and returns the string
// converted to an os.ErrorString, which satisfies the os.Error interface.
func Errorf(format string, a ...interface{}) os.Error {
- return os.ErrorString(Sprintf(format, a...))
+ return os.NewError(Sprintf(format, a...))
}
// These routines do not take a format string
@@ -363,6 +366,8 @@ func (p *pp) fmt0x64(v uint64, leading0x bool) {
// temporarily turning on the unicode flag and tweaking the precision.
func (p *pp) fmtUnicode(v int64) {
precPresent := p.fmt.precPresent
+ sharp := p.fmt.sharp
+ p.fmt.sharp = false
prec := p.fmt.prec
if !precPresent {
// If prec is already set, leave it alone; otherwise 4 is minimum.
@@ -370,10 +375,13 @@ func (p *pp) fmtUnicode(v int64) {
p.fmt.precPresent = true
}
p.fmt.unicode = true // turn on U+
+ p.fmt.uniQuote = sharp
p.fmt.integer(int64(v), 16, unsigned, udigits)
p.fmt.unicode = false
+ p.fmt.uniQuote = false
p.fmt.prec = prec
p.fmt.precPresent = precPresent
+ p.fmt.sharp = sharp
}
func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}) {
@@ -561,6 +569,31 @@ var (
uintptrBits = reflect.TypeOf(uintptr(0)).Bits()
)
+func (p *pp) catchPanic(val interface{}, verb int) {
+ if err := recover(); err != nil {
+ // If it's a nil pointer, just say "<nil>". The likeliest causes are a
+ // Stringer that fails to guard against nil or a nil pointer for a
+ // value receiver, and in either case, "<nil>" is a nice result.
+ if v := reflect.ValueOf(val); v.Kind() == reflect.Ptr && v.IsNil() {
+ p.buf.Write(nilAngleBytes)
+ return
+ }
+ // Otherwise print a concise panic message. Most of the time the panic
+ // value will print itself nicely.
+ if p.panicking {
+ // Nested panics; the recursion in printField cannot succeed.
+ panic(err)
+ }
+ p.buf.WriteByte('%')
+ p.add(verb)
+ p.buf.Write(panicBytes)
+ p.panicking = true
+ p.printField(err, 'v', false, false, 0)
+ p.panicking = false
+ p.buf.WriteByte(')')
+ }
+}
+
func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth int) (wasString bool) {
if field == nil {
if verb == 'T' || verb == 'v' {
@@ -583,6 +616,7 @@ func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth
}
// Is it a Formatter?
if formatter, ok := field.(Formatter); ok {
+ defer p.catchPanic(field, verb)
formatter.Format(p, verb)
return false // this value is not a string
@@ -595,6 +629,7 @@ func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth
if goSyntax {
p.fmt.sharp = false
if stringer, ok := field.(GoStringer); ok {
+ defer p.catchPanic(field, verb)
// Print the result of GoString unadorned.
p.fmtString(stringer.GoString(), 's', false, field)
return false // this value is not a string
@@ -602,6 +637,7 @@ func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth
} else {
// Is it a Stringer?
if stringer, ok := field.(Stringer); ok {
+ defer p.catchPanic(field, verb)
p.printField(stringer.String(), verb, plus, false, depth)
return false // this value is not a string
}
diff --git a/src/pkg/fmt/scan.go b/src/pkg/fmt/scan.go
index dd8548ceb..f48fcbb44 100644
--- a/src/pkg/fmt/scan.go
+++ b/src/pkg/fmt/scan.go
@@ -167,7 +167,7 @@ type ssave struct {
// satisfies io.Reader. It will never be called when used as
// intended, so there is no need to make it actually work.
func (s *ss) Read(buf []byte) (n int, err os.Error) {
- return 0, os.ErrorString("ScanState's Read should not be called. Use ReadRune")
+ return 0, os.NewError("ScanState's Read should not be called. Use ReadRune")
}
func (s *ss) ReadRune() (rune int, size int, err os.Error) {
@@ -241,7 +241,7 @@ func (s *ss) error(err os.Error) {
}
func (s *ss) errorString(err string) {
- panic(scanError{os.ErrorString(err)})
+ panic(scanError{os.NewError(err)})
}
func (s *ss) Token(skipSpace bool, f func(int) bool) (tok []byte, err os.Error) {
@@ -427,8 +427,8 @@ func (s *ss) typeError(field interface{}, expected string) {
s.errorString("expected field of type pointer to " + expected + "; found " + reflect.TypeOf(field).String())
}
-var complexError = os.ErrorString("syntax error scanning complex number")
-var boolError = os.ErrorString("syntax error scanning boolean")
+var complexError = os.NewError("syntax error scanning complex number")
+var boolError = os.NewError("syntax error scanning boolean")
// consume reads the next rune in the input and reports whether it is in the ok string.
// If accept is true, it puts the character into the input token.
@@ -945,7 +945,7 @@ func (s *ss) scanOne(verb int, field interface{}) {
// For now, can only handle (renamed) []byte.
typ := v.Type()
if typ.Elem().Kind() != reflect.Uint8 {
- goto CantHandle
+ s.errorString("Scan: can't handle type: " + val.Type().String())
}
str := s.convertString(verb)
v.Set(reflect.MakeSlice(typ, len(str), len(str)))
@@ -959,7 +959,6 @@ func (s *ss) scanOne(verb int, field interface{}) {
case reflect.Complex64, reflect.Complex128:
v.SetComplex(s.scanComplex(verb, v.Type().Bits()))
default:
- CantHandle:
s.errorString("Scan: can't handle type: " + val.Type().String())
}
}
diff --git a/src/pkg/fmt/scan_test.go b/src/pkg/fmt/scan_test.go
index a4de8adb1..98b3b5493 100644
--- a/src/pkg/fmt/scan_test.go
+++ b/src/pkg/fmt/scan_test.go
@@ -94,7 +94,7 @@ func (x *Xs) Scan(state ScanState, verb int) os.Error {
}
s := string(tok)
if !regexp.MustCompile("^" + string(verb) + "+$").MatchString(s) {
- return os.ErrorString("syntax error for xs")
+ return os.NewError("syntax error for xs")
}
*x = Xs(s)
return nil
@@ -818,7 +818,7 @@ func (r *RecursiveInt) Scan(state ScanState, verb int) (err os.Error) {
next := new(RecursiveInt)
_, err = Fscanf(state, ".%v", next)
if err != nil {
- if err == os.ErrorString("input does not match format") || err == io.ErrUnexpectedEOF {
+ if err == os.NewError("input does not match format") || err == io.ErrUnexpectedEOF {
err = nil
}
return
diff --git a/src/pkg/go/build/Makefile b/src/pkg/go/build/Makefile
index 4411940ae..349e00e80 100644
--- a/src/pkg/go/build/Makefile
+++ b/src/pkg/go/build/Makefile
@@ -11,7 +11,7 @@ GOFILES=\
path.go\
syslist.go\
-CLEANFILES+=syslist.go
+CLEANFILES+=syslist.go pkgtest/_obj cmdtest/_obj cgotest/_obj
include ../../../Make.pkg
diff --git a/src/pkg/go/build/build.go b/src/pkg/go/build/build.go
index 3cb8efe47..d83a6666e 100644
--- a/src/pkg/go/build/build.go
+++ b/src/pkg/go/build/build.go
@@ -11,34 +11,61 @@ import (
"fmt"
"os"
"path/filepath"
+ "regexp"
"runtime"
"strings"
)
-func (d *DirInfo) Build(targ string) ([]*Cmd, os.Error) {
- b := &build{obj: "_obj/"}
+// Build produces a build Script for the given package.
+func Build(tree *Tree, pkg string, info *DirInfo) (*Script, os.Error) {
+ s := &Script{}
+ b := &build{
+ script: s,
+ path: filepath.Join(tree.SrcDir(), pkg),
+ }
+ b.obj = b.abs("_obj") + string(filepath.Separator)
- goarch := runtime.GOARCH
+ b.goarch = runtime.GOARCH
if g := os.Getenv("GOARCH"); g != "" {
- goarch = g
+ b.goarch = g
}
var err os.Error
- b.arch, err = ArchChar(goarch)
+ b.arch, err = ArchChar(b.goarch)
if err != nil {
return nil, err
}
- var gofiles = d.GoFiles // .go files to be built with gc
- var ofiles []string // *.GOARCH files to be linked or packed
+ // add import object files to list of Inputs
+ for _, pkg := range info.Imports {
+ t, p, err := FindTree(pkg)
+ if err != nil && err != ErrNotFound {
+ // FindTree should always be able to suggest an import
+ // path and tree. The path must be malformed
+ // (for example, an absolute or relative path).
+ return nil, os.NewError("build: invalid import: " + pkg)
+ }
+ s.addInput(filepath.Join(t.PkgDir(), p+".a"))
+ }
+
+ // .go files to be built with gc
+ gofiles := b.abss(info.GoFiles...)
+ s.addInput(gofiles...)
+
+ var ofiles []string // object files to be linked or packed
// make build directory
b.mkdir(b.obj)
+ s.addIntermediate(b.obj)
// cgo
- if len(d.CgoFiles) > 0 {
- outGo, outObj := b.cgo(d.CgoFiles)
+ if len(info.CgoFiles) > 0 {
+ cgoFiles := b.abss(info.CgoFiles...)
+ s.addInput(cgoFiles...)
+ outGo, outObj := b.cgo(cgoFiles)
gofiles = append(gofiles, outGo...)
ofiles = append(ofiles, outObj...)
+ s.addIntermediate(outGo...)
+ s.addIntermediate(outObj...)
}
// compile
@@ -46,31 +73,136 @@ func (d *DirInfo) Build(targ string) ([]*Cmd, os.Error) {
ofile := b.obj + "_go_." + b.arch
b.gc(ofile, gofiles...)
ofiles = append(ofiles, ofile)
+ s.addIntermediate(ofile)
}
// assemble
- for _, sfile := range d.SFiles {
+ for _, sfile := range info.SFiles {
ofile := b.obj + sfile[:len(sfile)-1] + b.arch
+ sfile = b.abs(sfile)
+ s.addInput(sfile)
b.asm(ofile, sfile)
ofiles = append(ofiles, ofile)
+ s.addIntermediate(ofile)
}
if len(ofiles) == 0 {
return nil, os.NewError("make: no object files to build")
}
- if d.IsCommand() {
+ // choose target file
+ var targ string
+ if info.IsCommand() {
+ // use the last part of the import path as binary name
+ _, bin := filepath.Split(pkg)
+ if runtime.GOOS == "windows" {
+ bin += ".exe"
+ }
+ targ = filepath.Join(tree.BinDir(), bin)
+ } else {
+ targ = filepath.Join(tree.PkgDir(), pkg+".a")
+ }
+
+ // make target directory
+ targDir, _ := filepath.Split(targ)
+ b.mkdir(targDir)
+
+ // link binary or pack object
+ if info.IsCommand() {
b.ld(targ, ofiles...)
} else {
b.gopack(targ, ofiles...)
}
+ s.Output = append(s.Output, targ)
+
+ return b.script, nil
+}
+
+// A Script describes the build process for a Go package.
+// The Input, Intermediate, and Output fields are lists of absolute paths.
+type Script struct {
+ Cmd []*Cmd
+ Input []string
+ Intermediate []string
+ Output []string
+}
+
+func (s *Script) addInput(file ...string) {
+ s.Input = append(s.Input, file...)
+}
+
+func (s *Script) addIntermediate(file ...string) {
+ s.Intermediate = append(s.Intermediate, file...)
+}
+
+// Run runs the Script's Cmds in order.
+func (s *Script) Run() os.Error {
+ for _, c := range s.Cmd {
+ if err := c.Run(); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// Stale returns true if the build's inputs are newer than its outputs.
+func (s *Script) Stale() bool {
+ var latest int64
+ // get latest mtime of outputs
+ for _, file := range s.Output {
+ fi, err := os.Stat(file)
+ if err != nil {
+ // any error reading output files means stale
+ return true
+ }
+ if m := fi.Mtime_ns; m > latest {
+ latest = m
+ }
+ }
+ for _, file := range s.Input {
+ fi, err := os.Stat(file)
+ if err != nil || fi.Mtime_ns > latest {
+ // any error reading input files means stale
+ // (attempt to rebuild to figure out why)
+ return true
+ }
+ }
+ return false
+}
+
+// Clean removes the Script's Intermediate files.
+// It tries to remove every file and returns the first error it encounters.
+func (s *Script) Clean() (err os.Error) {
+ // Reverse order so that directories get removed after the files they contain.
+ for i := len(s.Intermediate) - 1; i >= 0; i-- {
+ if e := os.Remove(s.Intermediate[i]); err == nil {
+ err = e
+ }
+ }
+ return
+}
- return b.cmds, nil
+// Clean removes the Script's Intermediate and Output files.
+// It tries to remove every file and returns the first error it encounters.
+func (s *Script) Nuke() (err os.Error) {
+ // Reverse order so that directories get removed after the files they contain.
+ for i := len(s.Output) - 1; i >= 0; i-- {
+ if e := os.Remove(s.Output[i]); err == nil {
+ err = e
+ }
+ }
+ if e := s.Clean(); err == nil {
+ err = e
+ }
+ return
}
+// A Cmd describes an individual build command.
type Cmd struct {
Args []string // command-line
Stdout string // write standard output to this file, "" is passthrough
+ Dir string // working directory
+ Env []string // environment
Input []string // file paths (dependencies)
Output []string // file paths
}
@@ -79,14 +211,16 @@ func (c *Cmd) String() string {
return strings.Join(c.Args, " ")
}
-func (c *Cmd) Run(dir string) os.Error {
+// Run executes the Cmd.
+func (c *Cmd) Run() os.Error {
out := new(bytes.Buffer)
cmd := exec.Command(c.Args[0], c.Args[1:]...)
- cmd.Dir = dir
+ cmd.Dir = c.Dir
+ cmd.Env = c.Env
cmd.Stdout = out
cmd.Stderr = out
if c.Stdout != "" {
- f, err := os.Create(filepath.Join(dir, c.Stdout))
+ f, err := os.Create(c.Stdout)
if err != nil {
return err
}
@@ -99,15 +233,6 @@ func (c *Cmd) Run(dir string) os.Error {
return nil
}
-func (c *Cmd) Clean(dir string) (err os.Error) {
- for _, fn := range c.Output {
- if e := os.RemoveAll(fn); err == nil {
- err = e
- }
- }
- return
-}
-
// ArchChar returns the architecture character for the given goarch.
// For example, ArchChar("amd64") returns "6".
func ArchChar(goarch string) (string, os.Error) {
@@ -123,13 +248,30 @@ func ArchChar(goarch string) (string, os.Error) {
}
type build struct {
- cmds []*Cmd
- obj string
- arch string
+ script *Script
+ path string
+ obj string
+ goarch string
+ arch string
+}
+
+func (b *build) abs(file string) string {
+ if filepath.IsAbs(file) {
+ return file
+ }
+ return filepath.Join(b.path, file)
+}
+
+func (b *build) abss(file ...string) []string {
+ s := make([]string, len(file))
+ for i, f := range file {
+ s[i] = b.abs(f)
+ }
+ return s
}
func (b *build) add(c Cmd) {
- b.cmds = append(b.cmds, &c)
+ b.script.Cmd = append(b.script.Cmd, &c)
}
func (b *build) mkdir(name string) {
@@ -192,7 +334,7 @@ func (b *build) cc(ofile string, cfiles ...string) {
func (b *build) gccCompile(ofile, cfile string) {
b.add(Cmd{
- Args: gccArgs(b.arch, "-o", ofile, "-c", cfile),
+ Args: b.gccArgs("-o", ofile, "-c", cfile),
Input: []string{cfile},
Output: []string{ofile},
})
@@ -200,21 +342,26 @@ func (b *build) gccCompile(ofile, cfile string) {
func (b *build) gccLink(ofile string, ofiles ...string) {
b.add(Cmd{
- Args: append(gccArgs(b.arch, "-o", ofile), ofiles...),
+ Args: append(b.gccArgs("-o", ofile), ofiles...),
Input: ofiles,
Output: []string{ofile},
})
}
-func gccArgs(arch string, args ...string) []string {
+func (b *build) gccArgs(args ...string) []string {
// TODO(adg): HOST_CC
- m := "-m32"
- if arch == "6" {
- m = "-m64"
+ a := []string{"gcc", "-I", b.path, "-g", "-fPIC", "-O2"}
+ switch b.arch {
+ case "8":
+ a = append(a, "-m32")
+ case "6":
+ a = append(a, "-m64")
}
- return append([]string{"gcc", m, "-I", ".", "-g", "-fPIC", "-O2"}, args...)
+ return append(a, args...)
}
+var cgoRe = regexp.MustCompile(`[/\\:]`)
+
func (b *build) cgo(cgofiles []string) (outGo, outObj []string) {
// cgo
// TODO(adg): CGOPKGPATH
@@ -222,19 +369,24 @@ func (b *build) cgo(cgofiles []string) (outGo, outObj []string) {
gofiles := []string{b.obj + "_cgo_gotypes.go"}
cfiles := []string{b.obj + "_cgo_main.c", b.obj + "_cgo_export.c"}
for _, fn := range cgofiles {
- f := b.obj + fn[:len(fn)-2]
+ f := b.obj + cgoRe.ReplaceAllString(fn[:len(fn)-2], "_")
gofiles = append(gofiles, f+"cgo1.go")
cfiles = append(cfiles, f+"cgo2.c")
}
defunC := b.obj + "_cgo_defun.c"
- output := append([]string{defunC}, gofiles...)
- output = append(output, cfiles...)
+ output := append([]string{defunC}, cfiles...)
+ output = append(output, gofiles...)
b.add(Cmd{
Args: append([]string{"cgo", "--"}, cgofiles...),
+ Dir: b.path,
+ Env: append(os.Environ(), "GOARCH="+b.goarch),
Input: cgofiles,
Output: output,
})
outGo = append(outGo, gofiles...)
+ exportH := filepath.Join(b.path, "_cgo_export.h")
+ b.script.addIntermediate(defunC, exportH, b.obj+"_cgo_flags")
+ b.script.addIntermediate(cfiles...)
// cc _cgo_defun.c
defunObj := b.obj + "_cgo_defun." + b.arch
@@ -249,10 +401,13 @@ func (b *build) cgo(cgofiles []string) (outGo, outObj []string) {
linkobj = append(linkobj, ofile)
if !strings.HasSuffix(ofile, "_cgo_main.o") {
outObj = append(outObj, ofile)
+ } else {
+ b.script.addIntermediate(ofile)
}
}
- dynObj := b.obj + "_cgo1_.o"
+ dynObj := b.obj + "_cgo_.o"
b.gccLink(dynObj, linkobj...)
+ b.script.addIntermediate(dynObj)
// cgo -dynimport
importC := b.obj + "_cgo_import.c"
@@ -262,6 +417,7 @@ func (b *build) cgo(cgofiles []string) (outGo, outObj []string) {
Input: []string{dynObj},
Output: []string{importC},
})
+ b.script.addIntermediate(importC)
// cc _cgo_import.ARCH
importObj := b.obj + "_cgo_import." + b.arch
diff --git a/src/pkg/go/build/build_test.go b/src/pkg/go/build/build_test.go
index c543eddbd..e59d87672 100644
--- a/src/pkg/go/build/build_test.go
+++ b/src/pkg/go/build/build_test.go
@@ -5,53 +5,57 @@
package build
import (
- "os"
+ "exec"
"path/filepath"
- "runtime"
- "strings"
"testing"
)
-var buildDirs = []string{
- "pkg/path",
- "cmd/gofix",
- "pkg/big",
- "pkg/go/build/cgotest",
+var buildPkgs = []string{
+ "go/build/pkgtest",
+ "go/build/cmdtest",
+ "go/build/cgotest",
}
+const cmdtestOutput = "3"
+
func TestBuild(t *testing.T) {
- out, err := filepath.Abs("_test/out")
- if err != nil {
- t.Fatal(err)
- }
- for _, d := range buildDirs {
- if runtime.GOARCH == "arm" && strings.Contains(d, "/cgo") {
- // no cgo for arm, yet.
+ for _, pkg := range buildPkgs {
+ tree := Path[0] // Goroot
+ dir := filepath.Join(tree.SrcDir(), pkg)
+
+ info, err := ScanDir(dir, true)
+ if err != nil {
+ t.Error("ScanDir:", err)
continue
}
- dir := filepath.Join(runtime.GOROOT(), "src", d)
- testBuild(t, dir, out)
- }
-}
-func testBuild(t *testing.T, dir, targ string) {
- d, err := ScanDir(dir, true)
- if err != nil {
- t.Error(err)
- return
- }
- defer os.Remove(targ)
- cmds, err := d.Build(targ)
- if err != nil {
- t.Error(err)
- return
- }
- for _, c := range cmds {
- t.Log("Run:", c)
- err = c.Run(dir)
+ s, err := Build(tree, pkg, info)
if err != nil {
- t.Error(c, err)
- return
+ t.Error("Build:", err)
+ continue
+ }
+
+ if err := s.Run(); err != nil {
+ t.Error("Run:", err)
+ continue
}
+
+ if pkg == "go/build/cmdtest" {
+ bin := s.Output[0]
+ b, err := exec.Command(bin).CombinedOutput()
+ if err != nil {
+ t.Errorf("exec: %s: %v", bin, err)
+ continue
+ }
+ if string(b) != cmdtestOutput {
+ t.Errorf("cmdtest output: %s want: %s", b, cmdtestOutput)
+ }
+ }
+
+ defer func(s *Script) {
+ if err := s.Nuke(); err != nil {
+ t.Errorf("nuking: %v", err)
+ }
+ }(s)
}
}
diff --git a/src/pkg/go/build/cgotest/cgotest.go b/src/pkg/go/build/cgotest/cgotest.go
new file mode 100644
index 000000000..32b931861
--- /dev/null
+++ b/src/pkg/go/build/cgotest/cgotest.go
@@ -0,0 +1,12 @@
+// 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 cgotest
+
+/*
+char* greeting = "hello, world";
+*/
+import "C"
+
+var Greeting = C.GoString(C.greeting)
diff --git a/src/pkg/go/build/cgotest/file.go b/src/pkg/go/build/cgotest/file.go
deleted file mode 100644
index 3b2a2e7d9..000000000
--- a/src/pkg/go/build/cgotest/file.go
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
-A trivial example of wrapping a C library in Go.
-For a more complex example and explanation,
-see ../gmp/gmp.go.
-*/
-
-package stdio
-
-/*
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <errno.h>
-
-char* greeting = "hello, world";
-*/
-import "C"
-import "unsafe"
-
-type File C.FILE
-
-// TODO(brainman): uncomment once stdout and stderr references are working on Windows.
-//var Stdout = (*File)(C.stdout)
-//var Stderr = (*File)(C.stderr)
-
-// Test reference to library symbol.
-// Stdout and stderr are too special to be a reliable test.
-var myerr = C.sys_errlist
-
-func (f *File) WriteString(s string) {
- p := C.CString(s)
- C.fputs(p, (*C.FILE)(f))
- C.free(unsafe.Pointer(p))
- f.Flush()
-}
-
-func (f *File) Flush() {
- C.fflush((*C.FILE)(f))
-}
-
-var Greeting = C.GoString(C.greeting)
diff --git a/src/pkg/go/build/cmdtest/main.go b/src/pkg/go/build/cmdtest/main.go
new file mode 100644
index 000000000..bed4f485a
--- /dev/null
+++ b/src/pkg/go/build/cmdtest/main.go
@@ -0,0 +1,12 @@
+// 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 main
+
+import "go/build/pkgtest"
+
+func main() {
+ pkgtest.Foo()
+ print(int(pkgtest.Sqrt(9)))
+}
diff --git a/src/pkg/go/build/dir.go b/src/pkg/go/build/dir.go
index 77e80bff0..20f8f2913 100644
--- a/src/pkg/go/build/dir.go
+++ b/src/pkg/go/build/dir.go
@@ -50,7 +50,6 @@ func ScanDir(dir string, allowMain bool) (info *DirInfo, err os.Error) {
var di DirInfo
imported := make(map[string]bool)
- pkgName := ""
fset := token.NewFileSet()
for i := range dirs {
d := &dirs[i]
@@ -89,17 +88,17 @@ func ScanDir(dir string, allowMain bool) (info *DirInfo, err os.Error) {
if s == "documentation" {
continue
}
- if pkgName == "" {
- pkgName = s
- } else if pkgName != s {
+ if di.PkgName == "" {
+ di.PkgName = s
+ } else if di.PkgName != s {
// Only if all files in the directory are in package main
- // do we return pkgName=="main".
+ // do we return PkgName=="main".
// A mix of main and another package reverts
// to the original (allowMain=false) behaviour.
- if s == "main" || pkgName == "main" {
+ if s == "main" || di.PkgName == "main" {
return ScanDir(dir, false)
}
- return nil, os.ErrorString("multiple package names in " + dir)
+ return nil, os.NewError("multiple package names in " + dir)
}
isCgo := false
for _, spec := range pf.Imports {
diff --git a/src/pkg/go/build/pkgtest/pkgtest.go b/src/pkg/go/build/pkgtest/pkgtest.go
new file mode 100644
index 000000000..9322f5ebd
--- /dev/null
+++ b/src/pkg/go/build/pkgtest/pkgtest.go
@@ -0,0 +1,9 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pkgtest
+
+func Foo() {}
+
+func Sqrt(x float64) float64
diff --git a/src/pkg/go/build/pkgtest/sqrt_386.s b/src/pkg/go/build/pkgtest/sqrt_386.s
new file mode 100644
index 000000000..d0a428d52
--- /dev/null
+++ b/src/pkg/go/build/pkgtest/sqrt_386.s
@@ -0,0 +1,10 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// func Sqrt(x float64) float64
+TEXT ·Sqrt(SB),7,$0
+ FMOVD x+0(FP),F0
+ FSQRT
+ FMOVDP F0,r+8(FP)
+ RET
diff --git a/src/pkg/go/build/pkgtest/sqrt_amd64.s b/src/pkg/go/build/pkgtest/sqrt_amd64.s
new file mode 100644
index 000000000..f5b329e70
--- /dev/null
+++ b/src/pkg/go/build/pkgtest/sqrt_amd64.s
@@ -0,0 +1,9 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// func Sqrt(x float64) float64
+TEXT ·Sqrt(SB),7,$0
+ SQRTSD x+0(FP), X0
+ MOVSD X0, r+8(FP)
+ RET
diff --git a/src/pkg/go/build/pkgtest/sqrt_arm.s b/src/pkg/go/build/pkgtest/sqrt_arm.s
new file mode 100644
index 000000000..befbb8a89
--- /dev/null
+++ b/src/pkg/go/build/pkgtest/sqrt_arm.s
@@ -0,0 +1,10 @@
+// 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.
+
+// func Sqrt(x float64) float64
+TEXT ·Sqrt(SB),7,$0
+ MOVD x+0(FP),F0
+ SQRTD F0,F0
+ MOVD F0,r+8(FP)
+ RET
diff --git a/src/pkg/go/parser/interface.go b/src/pkg/go/parser/interface.go
index b4780e057..1764c38e4 100644
--- a/src/pkg/go/parser/interface.go
+++ b/src/pkg/go/parser/interface.go
@@ -42,7 +42,7 @@ func readSource(filename string, src interface{}) ([]byte, os.Error) {
}
return buf.Bytes(), nil
default:
- return nil, os.ErrorString("invalid source")
+ return nil, os.NewError("invalid source")
}
}
diff --git a/src/pkg/go/printer/nodes.go b/src/pkg/go/printer/nodes.go
index 0fca8a161..f2b79d810 100644
--- a/src/pkg/go/printer/nodes.go
+++ b/src/pkg/go/printer/nodes.go
@@ -1158,8 +1158,14 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
case *ast.SelectStmt:
p.print(token.SELECT, blank)
- p.block(s.Body, 0)
- *multiLine = true
+ body := s.Body
+ if len(body.List) == 0 && !p.commentBefore(p.fset.Position(body.Rbrace)) {
+ // print empty select statement w/o comments on one line
+ p.print(body.Lbrace, token.LBRACE, body.Rbrace, token.RBRACE)
+ } else {
+ p.block(body, 0)
+ *multiLine = true
+ }
case *ast.ForStmt:
p.print(token.FOR)
diff --git a/src/pkg/go/printer/testdata/statements.golden b/src/pkg/go/printer/testdata/statements.golden
index 290060269..0e4840441 100644
--- a/src/pkg/go/printer/testdata/statements.golden
+++ b/src/pkg/go/printer/testdata/statements.golden
@@ -111,6 +111,21 @@ func _() {
}
+// Formatting of selected select statements.
+func _() {
+ select {}
+ select { /* this comment should not be tab-aligned because the closing } is on the same line */
+ }
+ select { /* this comment should be tab-aligned */
+ }
+ select { // this comment should be tab-aligned
+ }
+ select {
+ case <-c:
+ }
+}
+
+
// Formatting of for-statement headers.
func _() {
for {
diff --git a/src/pkg/go/printer/testdata/statements.input b/src/pkg/go/printer/testdata/statements.input
index 21e61efc4..86a753c5a 100644
--- a/src/pkg/go/printer/testdata/statements.input
+++ b/src/pkg/go/printer/testdata/statements.input
@@ -91,6 +91,19 @@ func _() {
}
+// Formatting of selected select statements.
+func _() {
+ select {
+ }
+ select { /* this comment should not be tab-aligned because the closing } is on the same line */ }
+ select { /* this comment should be tab-aligned */
+ }
+ select { // this comment should be tab-aligned
+ }
+ select { case <-c: }
+}
+
+
// Formatting of for-statement headers.
func _() {
for{}
diff --git a/src/pkg/go/scanner/scanner.go b/src/pkg/go/scanner/scanner.go
index 509abeca5..795f0ac15 100644
--- a/src/pkg/go/scanner/scanner.go
+++ b/src/pkg/go/scanner/scanner.go
@@ -22,6 +22,7 @@ package scanner
import (
"bytes"
+ "fmt"
"go/token"
"path/filepath"
"strconv"
@@ -674,7 +675,7 @@ scanAgain:
tok = S.switch3(token.OR, token.OR_ASSIGN, '|', token.LOR)
default:
if S.mode&AllowIllegalChars == 0 {
- S.error(offs, "illegal character "+strconv.QuoteRune(ch))
+ S.error(offs, fmt.Sprintf("illegal character %#U", ch))
}
insertSemi = S.insertSemi // preserve insertSemi info
}
diff --git a/src/pkg/go/scanner/scanner_test.go b/src/pkg/go/scanner/scanner_test.go
index ee1e830a1..c096e2725 100644
--- a/src/pkg/go/scanner/scanner_test.go
+++ b/src/pkg/go/scanner/scanner_test.go
@@ -650,9 +650,9 @@ var errors = []struct {
pos int
err string
}{
- {"\a", token.ILLEGAL, 0, "illegal character '\\a'"},
- {`#`, token.ILLEGAL, 0, "illegal character '#'"},
- {`…`, token.ILLEGAL, 0, "illegal character '…'"},
+ {"\a", token.ILLEGAL, 0, "illegal character U+0007"},
+ {`#`, token.ILLEGAL, 0, "illegal character U+0023 '#'"},
+ {`…`, token.ILLEGAL, 0, "illegal character U+2026 '…'"},
{`' '`, token.CHAR, 0, ""},
{`''`, token.CHAR, 0, "illegal character literal"},
{`'\8'`, token.CHAR, 2, "unknown escape sequence"},
diff --git a/src/pkg/go/types/exportdata.go b/src/pkg/go/types/exportdata.go
index cb08ffe18..f68133761 100644
--- a/src/pkg/go/types/exportdata.go
+++ b/src/pkg/go/types/exportdata.go
@@ -29,7 +29,7 @@ func readGopackHeader(buf *bufio.Reader) (name string, size int, err os.Error) {
s := strings.TrimSpace(string(hdr[64+12+6+6+8:][:10]))
size, err = strconv.Atoi(s)
if err != nil || hdr[len(hdr)-2] != '`' || hdr[len(hdr)-1] != '\n' {
- err = os.ErrorString("invalid archive header")
+ err = os.NewError("invalid archive header")
return
}
name = strings.TrimSpace(string(hdr[:64]))
@@ -80,7 +80,7 @@ func ExportData(filename string) (rc io.ReadCloser, err os.Error) {
return
}
if name != "__.SYMDEF" {
- err = os.ErrorString("go archive does not begin with __.SYMDEF")
+ err = os.NewError("go archive does not begin with __.SYMDEF")
return
}
const block = 4096
@@ -102,7 +102,7 @@ func ExportData(filename string) (rc io.ReadCloser, err os.Error) {
return
}
if name != "__.PKGDEF" {
- err = os.ErrorString("go archive is missing __.PKGDEF")
+ err = os.NewError("go archive is missing __.PKGDEF")
return
}
@@ -117,7 +117,7 @@ func ExportData(filename string) (rc io.ReadCloser, err os.Error) {
// Now at __.PKGDEF in archive or still at beginning of file.
// Either way, line should begin with "go object ".
if !strings.HasPrefix(string(line), "go object ") {
- err = os.ErrorString("not a go object file")
+ err = os.NewError("not a go object file")
return
}
diff --git a/src/pkg/go/types/gcimporter.go b/src/pkg/go/types/gcimporter.go
index 2cfed7726..aa0bb9160 100644
--- a/src/pkg/go/types/gcimporter.go
+++ b/src/pkg/go/types/gcimporter.go
@@ -124,7 +124,7 @@ func GcImporter(imports map[string]*ast.Object, path string) (pkg *ast.Object, e
filename, id := findPkg(path)
if filename == "" {
- err = os.ErrorString("can't find import: " + id)
+ err = os.NewError("can't find import: " + id)
return
}
@@ -166,7 +166,7 @@ func (e importError) String() string {
func (p *gcParser) error(err interface{}) {
if s, ok := err.(string); ok {
- err = os.ErrorString(s)
+ err = os.NewError(s)
}
// panic with a runtime.Error if err is not an os.Error
panic(importError{p.scanner.Pos(), err.(os.Error)})
diff --git a/src/pkg/gob/codec_test.go b/src/pkg/gob/codec_test.go
index 8961336cd..da8e59c74 100644
--- a/src/pkg/gob/codec_test.go
+++ b/src/pkg/gob/codec_test.go
@@ -330,7 +330,7 @@ func newDecodeStateFromData(data []byte) *decoderState {
// Test instruction execution for decoding.
// Do not run the machine yet; instead do individual instructions crafted by hand.
func TestScalarDecInstructions(t *testing.T) {
- ovfl := os.ErrorString("overflow")
+ ovfl := os.NewError("overflow")
// bool
{
diff --git a/src/pkg/gob/decode.go b/src/pkg/gob/decode.go
index 381d44c05..415b30825 100644
--- a/src/pkg/gob/decode.go
+++ b/src/pkg/gob/decode.go
@@ -17,9 +17,9 @@ import (
)
var (
- errBadUint = os.ErrorString("gob: encoded unsigned integer out of range")
- errBadType = os.ErrorString("gob: unknown type id or corrupted data")
- errRange = os.ErrorString("gob: bad data: field numbers out of bounds")
+ errBadUint = os.NewError("gob: encoded unsigned integer out of range")
+ errBadType = os.NewError("gob: unknown type id or corrupted data")
+ errRange = os.NewError("gob: bad data: field numbers out of bounds")
)
// decoderState is the execution state of an instance of the decoder. A new state
@@ -54,8 +54,8 @@ func (dec *Decoder) freeDecoderState(d *decoderState) {
dec.freeList = d
}
-func overflow(name string) os.ErrorString {
- return os.ErrorString(`value for "` + name + `" out of range`)
+func overflow(name string) os.Error {
+ return os.NewError(`value for "` + name + `" out of range`)
}
// decodeUintReader reads an encoded unsigned integer from an io.Reader.
@@ -135,10 +135,10 @@ type decOp func(i *decInstr, state *decoderState, p unsafe.Pointer)
// The 'instructions' of the decoding machine
type decInstr struct {
op decOp
- field int // field number of the wire type
- indir int // how many pointer indirections to reach the value in the struct
- offset uintptr // offset in the structure of the field to encode
- ovfl os.ErrorString // error message for overflow/underflow (for arrays, of the elements)
+ field int // field number of the wire type
+ indir int // how many pointer indirections to reach the value in the struct
+ offset uintptr // offset in the structure of the field to encode
+ ovfl os.Error // error message for overflow/underflow (for arrays, of the elements)
}
// Since the encoder writes no zeros, if we arrive at a decoder we have
@@ -367,7 +367,7 @@ func decComplex64(i *decInstr, state *decoderState, p unsafe.Pointer) {
p = *(*unsafe.Pointer)(p)
}
storeFloat32(i, state, p)
- storeFloat32(i, state, unsafe.Pointer(uintptr(p)+uintptr(unsafe.Sizeof(float32(0)))))
+ storeFloat32(i, state, unsafe.Pointer(uintptr(p)+unsafe.Sizeof(float32(0))))
}
// decComplex128 decodes a pair of unsigned integers, treats them as a
@@ -552,7 +552,7 @@ func (dec *Decoder) ignoreSingle(engine *decEngine) {
}
// decodeArrayHelper does the work for decoding arrays and slices.
-func (dec *Decoder) decodeArrayHelper(state *decoderState, p uintptr, elemOp decOp, elemWid uintptr, length, elemIndir int, ovfl os.ErrorString) {
+func (dec *Decoder) decodeArrayHelper(state *decoderState, p uintptr, elemOp decOp, elemWid uintptr, length, elemIndir int, ovfl os.Error) {
instr := &decInstr{elemOp, 0, elemIndir, 0, ovfl}
for i := 0; i < length; i++ {
up := unsafe.Pointer(p)
@@ -567,7 +567,7 @@ func (dec *Decoder) decodeArrayHelper(state *decoderState, p uintptr, elemOp dec
// decodeArray decodes an array and stores it through p, that is, p points to the zeroth element.
// The length is an unsigned integer preceding the elements. Even though the length is redundant
// (it's part of the type), it's a useful check and is included in the encoding.
-func (dec *Decoder) decodeArray(atyp reflect.Type, state *decoderState, p uintptr, elemOp decOp, elemWid uintptr, length, indir, elemIndir int, ovfl os.ErrorString) {
+func (dec *Decoder) decodeArray(atyp reflect.Type, state *decoderState, p uintptr, elemOp decOp, elemWid uintptr, length, indir, elemIndir int, ovfl os.Error) {
if indir > 0 {
p = allocate(atyp, p, 1) // All but the last level has been allocated by dec.Indirect
}
@@ -579,7 +579,7 @@ func (dec *Decoder) decodeArray(atyp reflect.Type, state *decoderState, p uintpt
// decodeIntoValue is a helper for map decoding. Since maps are decoded using reflection,
// unlike the other items we can't use a pointer directly.
-func decodeIntoValue(state *decoderState, op decOp, indir int, v reflect.Value, ovfl os.ErrorString) reflect.Value {
+func decodeIntoValue(state *decoderState, op decOp, indir int, v reflect.Value, ovfl os.Error) reflect.Value {
instr := &decInstr{op, 0, indir, 0, ovfl}
up := unsafe.Pointer(unsafeAddr(v))
if indir > 1 {
@@ -593,7 +593,7 @@ func decodeIntoValue(state *decoderState, op decOp, indir int, v reflect.Value,
// Maps are encoded as a length followed by key:value pairs.
// Because the internals of maps are not visible to us, we must
// use reflection rather than pointer magic.
-func (dec *Decoder) decodeMap(mtyp reflect.Type, state *decoderState, p uintptr, keyOp, elemOp decOp, indir, keyIndir, elemIndir int, ovfl os.ErrorString) {
+func (dec *Decoder) decodeMap(mtyp reflect.Type, state *decoderState, p uintptr, keyOp, elemOp decOp, indir, keyIndir, elemIndir int, ovfl os.Error) {
if indir > 0 {
p = allocate(mtyp, p, 1) // All but the last level has been allocated by dec.Indirect
}
@@ -616,7 +616,7 @@ func (dec *Decoder) decodeMap(mtyp reflect.Type, state *decoderState, p uintptr,
// ignoreArrayHelper does the work for discarding arrays and slices.
func (dec *Decoder) ignoreArrayHelper(state *decoderState, elemOp decOp, length int) {
- instr := &decInstr{elemOp, 0, 0, 0, os.ErrorString("no error")}
+ instr := &decInstr{elemOp, 0, 0, 0, os.NewError("no error")}
for i := 0; i < length; i++ {
elemOp(instr, state, nil)
}
@@ -633,8 +633,8 @@ func (dec *Decoder) ignoreArray(state *decoderState, elemOp decOp, length int) {
// ignoreMap discards the data for a map value with no destination.
func (dec *Decoder) ignoreMap(state *decoderState, keyOp, elemOp decOp) {
n := int(state.decodeUint())
- keyInstr := &decInstr{keyOp, 0, 0, 0, os.ErrorString("no error")}
- elemInstr := &decInstr{elemOp, 0, 0, 0, os.ErrorString("no error")}
+ keyInstr := &decInstr{keyOp, 0, 0, 0, os.NewError("no error")}
+ elemInstr := &decInstr{elemOp, 0, 0, 0, os.NewError("no error")}
for i := 0; i < n; i++ {
keyOp(keyInstr, state, nil)
elemOp(elemInstr, state, nil)
@@ -643,7 +643,7 @@ func (dec *Decoder) ignoreMap(state *decoderState, keyOp, elemOp decOp) {
// decodeSlice decodes a slice and stores the slice header through p.
// Slices are encoded as an unsigned length followed by the elements.
-func (dec *Decoder) decodeSlice(atyp reflect.Type, state *decoderState, p uintptr, elemOp decOp, elemWid uintptr, indir, elemIndir int, ovfl os.ErrorString) {
+func (dec *Decoder) decodeSlice(atyp reflect.Type, state *decoderState, p uintptr, elemOp decOp, elemWid uintptr, indir, elemIndir int, ovfl os.Error) {
n := int(uintptr(state.decodeUint()))
if indir > 0 {
up := unsafe.Pointer(p)
@@ -1064,10 +1064,10 @@ func (dec *Decoder) compileSingle(remoteId typeId, ut *userTypeInfo) (engine *de
engine.instr = make([]decInstr, 1) // one item
name := rt.String() // best we can do
if !dec.compatibleType(rt, remoteId, make(map[reflect.Type]typeId)) {
- return nil, os.ErrorString("gob: wrong type received for local value " + name + ": " + dec.typeString(remoteId))
+ return nil, os.NewError("gob: wrong type received for local value " + name + ": " + dec.typeString(remoteId))
}
op, indir := dec.decOpFor(remoteId, rt, name, make(map[reflect.Type]*decOp))
- ovfl := os.ErrorString(`value for "` + name + `" out of range`)
+ ovfl := os.NewError(`value for "` + name + `" out of range`)
engine.instr[singletonField] = decInstr{*op, singletonField, indir, 0, ovfl}
engine.numInstr = 1
return
diff --git a/src/pkg/gob/decoder.go b/src/pkg/gob/decoder.go
index b83904a71..281947132 100644
--- a/src/pkg/gob/decoder.go
+++ b/src/pkg/gob/decoder.go
@@ -44,7 +44,7 @@ func NewDecoder(r io.Reader) *Decoder {
func (dec *Decoder) recvType(id typeId) {
// Have we already seen this type? That's an error
if id < firstUserId || dec.wireType[id] != nil {
- dec.err = os.ErrorString("gob: duplicate type received")
+ dec.err = os.NewError("gob: duplicate type received")
return
}
@@ -143,7 +143,7 @@ func (dec *Decoder) decodeTypeSequence(isInterface bool) typeId {
// will be absorbed by recvMessage.)
if dec.buf.Len() > 0 {
if !isInterface {
- dec.err = os.ErrorString("extra data in buffer")
+ dec.err = os.NewError("extra data in buffer")
break
}
dec.nextUint()
@@ -165,7 +165,7 @@ func (dec *Decoder) Decode(e interface{}) os.Error {
// If e represents a value as opposed to a pointer, the answer won't
// get back to the caller. Make sure it's a pointer.
if value.Type().Kind() != reflect.Ptr {
- dec.err = os.ErrorString("gob: attempt to decode into a non-pointer")
+ dec.err = os.NewError("gob: attempt to decode into a non-pointer")
return dec.err
}
return dec.DecodeValue(value)
@@ -180,7 +180,7 @@ func (dec *Decoder) DecodeValue(v reflect.Value) os.Error {
if v.Kind() == reflect.Ptr && !v.IsNil() {
// That's okay, we'll store through the pointer.
} else if !v.CanSet() {
- return os.ErrorString("gob: DecodeValue of unassignable value")
+ return os.NewError("gob: DecodeValue of unassignable value")
}
}
// Make sure we're single-threaded through here.
diff --git a/src/pkg/gob/encode.go b/src/pkg/gob/encode.go
index f9e691a2f..743e853e9 100644
--- a/src/pkg/gob/encode.go
+++ b/src/pkg/gob/encode.go
@@ -11,7 +11,7 @@ import (
"unsafe"
)
-const uint64Size = unsafe.Sizeof(uint64(0))
+const uint64Size = int(unsafe.Sizeof(uint64(0)))
// encoderState is the global execution state of an instance of the encoder.
// Field numbers are delta encoded and always increase. The field
diff --git a/src/pkg/gob/encoder.go b/src/pkg/gob/encoder.go
index 65ee5bf67..96101d92b 100644
--- a/src/pkg/gob/encoder.go
+++ b/src/pkg/gob/encoder.go
@@ -50,7 +50,7 @@ func (enc *Encoder) popWriter() {
}
func (enc *Encoder) badType(rt reflect.Type) {
- enc.setError(os.ErrorString("gob: can't encode type " + rt.String()))
+ enc.setError(os.NewError("gob: can't encode type " + rt.String()))
}
func (enc *Encoder) setError(err os.Error) {
diff --git a/src/pkg/gob/gobencdec_test.go b/src/pkg/gob/gobencdec_test.go
index 3e1906020..25cb5d11b 100644
--- a/src/pkg/gob/gobencdec_test.go
+++ b/src/pkg/gob/gobencdec_test.go
@@ -44,7 +44,7 @@ func (g *ByteStruct) GobEncode() ([]byte, os.Error) {
func (g *ByteStruct) GobDecode(data []byte) os.Error {
if g == nil {
- return os.ErrorString("NIL RECEIVER")
+ return os.NewError("NIL RECEIVER")
}
// Expect N sequential-valued bytes.
if len(data) == 0 {
@@ -53,7 +53,7 @@ func (g *ByteStruct) GobDecode(data []byte) os.Error {
g.a = data[0]
for i, c := range data {
if c != g.a+byte(i) {
- return os.ErrorString("invalid data sequence")
+ return os.NewError("invalid data sequence")
}
}
return nil
@@ -71,7 +71,7 @@ func (g *StringStruct) GobDecode(data []byte) os.Error {
a := data[0]
for i, c := range data {
if c != a+byte(i) {
- return os.ErrorString("invalid data sequence")
+ return os.NewError("invalid data sequence")
}
}
g.s = string(data)
@@ -84,7 +84,7 @@ func (a *ArrayStruct) GobEncode() ([]byte, os.Error) {
func (a *ArrayStruct) GobDecode(data []byte) os.Error {
if len(data) != len(a.a) {
- return os.ErrorString("wrong length in array decode")
+ return os.NewError("wrong length in array decode")
}
copy(a.a[:], data)
return nil
diff --git a/src/pkg/gob/type.go b/src/pkg/gob/type.go
index c6542633a..f8e3843a7 100644
--- a/src/pkg/gob/type.go
+++ b/src/pkg/gob/type.go
@@ -67,7 +67,7 @@ func validUserType(rt reflect.Type) (ut *userTypeInfo, err os.Error) {
ut.base = pt.Elem()
if ut.base == slowpoke { // ut.base lapped slowpoke
// recursive pointer type.
- return nil, os.ErrorString("can't represent recursive pointer type " + ut.base.String())
+ return nil, os.NewError("can't represent recursive pointer type " + ut.base.String())
}
if ut.indir%2 == 0 {
slowpoke = slowpoke.Elem()
@@ -508,7 +508,7 @@ func newTypeObject(name string, ut *userTypeInfo, rt reflect.Type) (gobType, os.
return st, nil
default:
- return nil, os.ErrorString("gob NewTypeObject can't handle type: " + rt.String())
+ return nil, os.NewError("gob NewTypeObject can't handle type: " + rt.String())
}
return nil, nil
}
diff --git a/src/pkg/hash/fnv/fnv.go b/src/pkg/hash/fnv/fnv.go
index 9a1c6a0f2..3ff7d7c75 100644
--- a/src/pkg/hash/fnv/fnv.go
+++ b/src/pkg/hash/fnv/fnv.go
@@ -11,7 +11,6 @@ import (
"encoding/binary"
"hash"
"os"
- "unsafe"
)
type (
@@ -102,31 +101,31 @@ func (s *sum64a) Write(data []byte) (int, os.Error) {
return len(data), nil
}
-func (s *sum32) Size() int { return unsafe.Sizeof(*s) }
-func (s *sum32a) Size() int { return unsafe.Sizeof(*s) }
-func (s *sum64) Size() int { return unsafe.Sizeof(*s) }
-func (s *sum64a) Size() int { return unsafe.Sizeof(*s) }
+func (s *sum32) Size() int { return 4 }
+func (s *sum32a) Size() int { return 4 }
+func (s *sum64) Size() int { return 8 }
+func (s *sum64a) Size() int { return 8 }
func (s *sum32) Sum() []byte {
- a := make([]byte, unsafe.Sizeof(*s))
+ a := make([]byte, 4)
binary.BigEndian.PutUint32(a, uint32(*s))
return a
}
func (s *sum32a) Sum() []byte {
- a := make([]byte, unsafe.Sizeof(*s))
+ a := make([]byte, 4)
binary.BigEndian.PutUint32(a, uint32(*s))
return a
}
func (s *sum64) Sum() []byte {
- a := make([]byte, unsafe.Sizeof(*s))
+ a := make([]byte, 8)
binary.BigEndian.PutUint64(a, uint64(*s))
return a
}
func (s *sum64a) Sum() []byte {
- a := make([]byte, unsafe.Sizeof(*s))
+ a := make([]byte, 8)
binary.BigEndian.PutUint64(a, uint64(*s))
return a
}
diff --git a/src/pkg/http/cgi/child.go b/src/pkg/http/cgi/child.go
index e1ad7ad32..8b74d7054 100644
--- a/src/pkg/http/cgi/child.go
+++ b/src/pkg/http/cgi/child.go
@@ -45,13 +45,6 @@ func envMap(env []string) map[string]string {
return m
}
-// These environment variables are manually copied into Request
-var skipHeader = map[string]bool{
- "HTTP_HOST": true,
- "HTTP_REFERER": true,
- "HTTP_USER_AGENT": true,
-}
-
// RequestFromMap creates an http.Request from CGI variables.
// The returned Request's Body field is not populated.
func RequestFromMap(params map[string]string) (*http.Request, os.Error) {
@@ -73,8 +66,6 @@ func RequestFromMap(params map[string]string) (*http.Request, os.Error) {
r.Header = http.Header{}
r.Host = params["HTTP_HOST"]
- r.Referer = params["HTTP_REFERER"]
- r.UserAgent = params["HTTP_USER_AGENT"]
if lenstr := params["CONTENT_LENGTH"]; lenstr != "" {
clen, err := strconv.Atoi64(lenstr)
@@ -90,7 +81,7 @@ func RequestFromMap(params map[string]string) (*http.Request, os.Error) {
// Copy "HTTP_FOO_BAR" variables to "Foo-Bar" Headers
for k, v := range params {
- if !strings.HasPrefix(k, "HTTP_") || skipHeader[k] {
+ if !strings.HasPrefix(k, "HTTP_") || k == "HTTP_HOST" {
continue
}
r.Header.Add(strings.Replace(k[5:], "_", "-", -1), v)
diff --git a/src/pkg/http/cgi/child_test.go b/src/pkg/http/cgi/child_test.go
index d12947814..eee043bc9 100644
--- a/src/pkg/http/cgi/child_test.go
+++ b/src/pkg/http/cgi/child_test.go
@@ -28,23 +28,19 @@ func TestRequest(t *testing.T) {
if err != nil {
t.Fatalf("RequestFromMap: %v", err)
}
- if g, e := req.UserAgent, "goclient"; e != g {
+ if g, e := req.UserAgent(), "goclient"; e != g {
t.Errorf("expected UserAgent %q; got %q", e, g)
}
if g, e := req.Method, "GET"; e != g {
t.Errorf("expected Method %q; got %q", e, g)
}
- if g, e := req.Header.Get("User-Agent"), ""; e != g {
- // Tests that we don't put recognized headers in the map
- t.Errorf("expected User-Agent %q; got %q", e, g)
- }
if g, e := req.Header.Get("Content-Type"), "text/xml"; e != g {
t.Errorf("expected Content-Type %q; got %q", e, g)
}
if g, e := req.ContentLength, int64(123); e != g {
t.Errorf("expected ContentLength %d; got %d", e, g)
}
- if g, e := req.Referer, "elsewhere"; e != g {
+ if g, e := req.Referer(), "elsewhere"; e != g {
t.Errorf("expected Referer %q; got %q", e, g)
}
if req.Header == nil {
diff --git a/src/pkg/http/cgi/host.go b/src/pkg/http/cgi/host.go
index 7ab3f9247..2be3ede77 100644
--- a/src/pkg/http/cgi/host.go
+++ b/src/pkg/http/cgi/host.go
@@ -16,7 +16,6 @@ package cgi
import (
"bufio"
- "bytes"
"exec"
"fmt"
"http"
@@ -106,20 +105,13 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
env = append(env, "HTTPS=on")
}
- if len(req.Cookie) > 0 {
- b := new(bytes.Buffer)
- for idx, c := range req.Cookie {
- if idx > 0 {
- b.Write([]byte("; "))
- }
- fmt.Fprintf(b, "%s=%s", c.Name, c.Value)
- }
- env = append(env, "HTTP_COOKIE="+b.String())
- }
-
for k, v := range req.Header {
k = strings.Map(upperCaseAndUnderscore, k)
- env = append(env, "HTTP_"+k+"="+strings.Join(v, ", "))
+ joinStr := ", "
+ if k == "COOKIE" {
+ joinStr = "; "
+ }
+ env = append(env, "HTTP_"+k+"="+strings.Join(v, joinStr))
}
if req.ContentLength > 0 {
diff --git a/src/pkg/http/client.go b/src/pkg/http/client.go
index 71b037042..4f63b44f2 100644
--- a/src/pkg/http/client.go
+++ b/src/pkg/http/client.go
@@ -16,6 +16,11 @@ import (
// A Client is an HTTP client. Its zero value (DefaultClient) is a usable client
// that uses DefaultTransport.
+//
+// The Client's Transport typically has internal state (cached
+// TCP connections), so Clients should be reused instead of created as
+// needed. Clients are safe for concurrent use by multiple goroutines.
+//
// Client is not yet very configurable.
type Client struct {
Transport RoundTripper // if nil, DefaultTransport is used
@@ -36,6 +41,9 @@ var DefaultClient = &Client{}
// RoundTripper is an interface representing the ability to execute a
// single HTTP transaction, obtaining the Response for a given Request.
+//
+// A RoundTripper must be safe for concurrent use by multiple
+// goroutines.
type RoundTripper interface {
// RoundTrip executes a single HTTP transaction, returning
// the Response for the request req. RoundTrip should not
@@ -173,7 +181,7 @@ func (c *Client) doFollowingRedirects(ireq *Request) (r *Response, err os.Error)
// Add the Referer header.
lastReq := via[len(via)-1]
if lastReq.URL.Scheme != "https" {
- req.Referer = lastReq.URL.String()
+ req.Header.Set("Referer", lastReq.URL.String())
}
err = redirectChecker(req, via)
@@ -190,7 +198,7 @@ func (c *Client) doFollowingRedirects(ireq *Request) (r *Response, err os.Error)
if shouldRedirect(r.StatusCode) {
r.Body.Close()
if url = r.Header.Get("Location"); url == "" {
- err = os.ErrorString(fmt.Sprintf("%d response missing Location header", r.StatusCode))
+ err = os.NewError(fmt.Sprintf("%d response missing Location header", r.StatusCode))
break
}
base = req.URL
@@ -207,7 +215,7 @@ func (c *Client) doFollowingRedirects(ireq *Request) (r *Response, err os.Error)
func defaultCheckRedirect(req *Request, via []*Request) os.Error {
if len(via) >= 10 {
- return os.ErrorString("stopped after 10 redirects")
+ return os.NewError("stopped after 10 redirects")
}
return nil
}
diff --git a/src/pkg/http/client_test.go b/src/pkg/http/client_test.go
index 9ef81d9d4..3b8558535 100644
--- a/src/pkg/http/client_test.go
+++ b/src/pkg/http/client_test.go
@@ -12,6 +12,7 @@ import (
"http/httptest"
"io"
"io/ioutil"
+ "net"
"os"
"strconv"
"strings"
@@ -149,7 +150,7 @@ func TestRedirects(t *testing.T) {
n, _ := strconv.Atoi(r.FormValue("n"))
// Test Referer header. (7 is arbitrary position to test at)
if n == 7 {
- if g, e := r.Referer, ts.URL+"/?n=6"; e != g {
+ if g, e := r.Referer(), ts.URL+"/?n=6"; e != g {
t.Errorf("on request ?n=7, expected referer of %q; got %q", e, g)
}
}
@@ -243,3 +244,48 @@ func TestStreamingGet(t *testing.T) {
t.Fatalf("at end expected EOF, got %v", err)
}
}
+
+type writeCountingConn struct {
+ net.Conn
+ count *int
+}
+
+func (c *writeCountingConn) Write(p []byte) (int, os.Error) {
+ *c.count++
+ return c.Conn.Write(p)
+}
+
+// TestClientWrites verifies that client requests are buffered and we
+// don't send a TCP packet per line of the http request + body.
+func TestClientWrites(t *testing.T) {
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ }))
+ defer ts.Close()
+
+ writes := 0
+ dialer := func(netz string, addr string) (net.Conn, os.Error) {
+ c, err := net.Dial(netz, addr)
+ if err == nil {
+ c = &writeCountingConn{c, &writes}
+ }
+ return c, err
+ }
+ c := &Client{Transport: &Transport{Dial: dialer}}
+
+ _, err := c.Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if writes != 1 {
+ t.Errorf("Get request did %d Write calls, want 1", writes)
+ }
+
+ writes = 0
+ _, err = c.PostForm(ts.URL, Values{"foo": {"bar"}})
+ if err != nil {
+ t.Fatal(err)
+ }
+ if writes != 1 {
+ t.Errorf("Post request did %d Write calls, want 1", writes)
+ }
+}
diff --git a/src/pkg/http/cookie.go b/src/pkg/http/cookie.go
index eb61a7001..79c239b46 100644
--- a/src/pkg/http/cookie.go
+++ b/src/pkg/http/cookie.go
@@ -7,9 +7,6 @@ package http
import (
"bytes"
"fmt"
- "io"
- "os"
- "sort"
"strconv"
"strings"
"time"
@@ -40,11 +37,9 @@ type Cookie struct {
}
// readSetCookies parses all "Set-Cookie" values from
-// the header h, removes the successfully parsed values from the
-// "Set-Cookie" key in h and returns the parsed Cookies.
+// the header h and returns the successfully parsed Cookies.
func readSetCookies(h Header) []*Cookie {
cookies := []*Cookie{}
- var unparsedLines []string
for _, line := range h["Set-Cookie"] {
parts := strings.Split(strings.TrimSpace(line), ";", -1)
if len(parts) == 1 && parts[0] == "" {
@@ -53,17 +48,14 @@ func readSetCookies(h Header) []*Cookie {
parts[0] = strings.TrimSpace(parts[0])
j := strings.Index(parts[0], "=")
if j < 0 {
- unparsedLines = append(unparsedLines, line)
continue
}
name, value := parts[0][:j], parts[0][j+1:]
if !isCookieNameValid(name) {
- unparsedLines = append(unparsedLines, line)
continue
}
value, success := parseCookieValue(value)
if !success {
- unparsedLines = append(unparsedLines, line)
continue
}
c := &Cookie{
@@ -134,75 +126,54 @@ func readSetCookies(h Header) []*Cookie {
}
cookies = append(cookies, c)
}
- h["Set-Cookie"] = unparsedLines, unparsedLines != nil
return cookies
}
// SetCookie adds a Set-Cookie header to the provided ResponseWriter's headers.
func SetCookie(w ResponseWriter, cookie *Cookie) {
- var b bytes.Buffer
- writeSetCookieToBuffer(&b, cookie)
- w.Header().Add("Set-Cookie", b.String())
+ w.Header().Add("Set-Cookie", cookie.String())
}
-func writeSetCookieToBuffer(buf *bytes.Buffer, c *Cookie) {
- fmt.Fprintf(buf, "%s=%s", sanitizeName(c.Name), sanitizeValue(c.Value))
+// String returns the serialization of the cookie for use in a Cookie
+// header (if only Name and Value are set) or a Set-Cookie response
+// header (if other fields are set).
+func (c *Cookie) String() string {
+ var b bytes.Buffer
+ fmt.Fprintf(&b, "%s=%s", sanitizeName(c.Name), sanitizeValue(c.Value))
if len(c.Path) > 0 {
- fmt.Fprintf(buf, "; Path=%s", sanitizeValue(c.Path))
+ fmt.Fprintf(&b, "; Path=%s", sanitizeValue(c.Path))
}
if len(c.Domain) > 0 {
- fmt.Fprintf(buf, "; Domain=%s", sanitizeValue(c.Domain))
+ fmt.Fprintf(&b, "; Domain=%s", sanitizeValue(c.Domain))
}
if len(c.Expires.Zone) > 0 {
- fmt.Fprintf(buf, "; Expires=%s", c.Expires.Format(time.RFC1123))
+ fmt.Fprintf(&b, "; Expires=%s", c.Expires.Format(time.RFC1123))
}
if c.MaxAge > 0 {
- fmt.Fprintf(buf, "; Max-Age=%d", c.MaxAge)
+ fmt.Fprintf(&b, "; Max-Age=%d", c.MaxAge)
} else if c.MaxAge < 0 {
- fmt.Fprintf(buf, "; Max-Age=0")
+ fmt.Fprintf(&b, "; Max-Age=0")
}
if c.HttpOnly {
- fmt.Fprintf(buf, "; HttpOnly")
+ fmt.Fprintf(&b, "; HttpOnly")
}
if c.Secure {
- fmt.Fprintf(buf, "; Secure")
+ fmt.Fprintf(&b, "; Secure")
}
+ return b.String()
}
-// writeSetCookies writes the wire representation of the set-cookies
-// to w. Each cookie is written on a separate "Set-Cookie: " line.
-// This choice is made because HTTP parsers tend to have a limit on
-// line-length, so it seems safer to place cookies on separate lines.
-func writeSetCookies(w io.Writer, kk []*Cookie) os.Error {
- if kk == nil {
- return nil
- }
- lines := make([]string, 0, len(kk))
- var b bytes.Buffer
- for _, c := range kk {
- b.Reset()
- writeSetCookieToBuffer(&b, c)
- lines = append(lines, "Set-Cookie: "+b.String()+"\r\n")
- }
- sort.SortStrings(lines)
- for _, l := range lines {
- if _, err := io.WriteString(w, l); err != nil {
- return err
- }
- }
- return nil
-}
-
-// readCookies parses all "Cookie" values from
-// the header h, removes the successfully parsed values from the
-// "Cookie" key in h and returns the parsed Cookies.
-func readCookies(h Header) []*Cookie {
+// readCookies parses all "Cookie" values from the header h and
+// returns the successfully parsed Cookies.
+//
+// if filter isn't empty, only cookies of that name are returned
+func readCookies(h Header, filter string) []*Cookie {
cookies := []*Cookie{}
lines, ok := h["Cookie"]
if !ok {
return cookies
}
- unparsedLines := []string{}
+
for _, line := range lines {
parts := strings.Split(strings.TrimSpace(line), ";", -1)
if len(parts) == 1 && parts[0] == "" {
@@ -215,50 +186,27 @@ func readCookies(h Header) []*Cookie {
if len(parts[i]) == 0 {
continue
}
- attr, val := parts[i], ""
- if j := strings.Index(attr, "="); j >= 0 {
- attr, val = attr[:j], attr[j+1:]
+ name, val := parts[i], ""
+ if j := strings.Index(name, "="); j >= 0 {
+ name, val = name[:j], name[j+1:]
}
- if !isCookieNameValid(attr) {
+ if !isCookieNameValid(name) {
+ continue
+ }
+ if filter != "" && filter != name {
continue
}
val, success := parseCookieValue(val)
if !success {
continue
}
- cookies = append(cookies, &Cookie{Name: attr, Value: val})
+ cookies = append(cookies, &Cookie{Name: name, Value: val})
parsedPairs++
}
- if parsedPairs == 0 {
- unparsedLines = append(unparsedLines, line)
- }
}
- h["Cookie"] = unparsedLines, len(unparsedLines) > 0
return cookies
}
-// writeCookies writes the wire representation of the cookies to
-// w. According to RFC 6265 section 5.4, writeCookies does not
-// attach more than one Cookie header field. That means all
-// cookies, if any, are written into the same line, separated by
-// semicolon.
-func writeCookies(w io.Writer, kk []*Cookie) os.Error {
- if len(kk) == 0 {
- return nil
- }
- var buf bytes.Buffer
- fmt.Fprintf(&buf, "Cookie: ")
- for i, c := range kk {
- if i > 0 {
- fmt.Fprintf(&buf, "; ")
- }
- fmt.Fprintf(&buf, "%s=%s", sanitizeName(c.Name), sanitizeValue(c.Value))
- }
- fmt.Fprintf(&buf, "\r\n")
- _, err := w.Write(buf.Bytes())
- return err
-}
-
func sanitizeName(n string) string {
n = strings.Replace(n, "\n", "-", -1)
n = strings.Replace(n, "\r", "-", -1)
diff --git a/src/pkg/http/cookie_test.go b/src/pkg/http/cookie_test.go
index 02e42226b..d7aeda0be 100644
--- a/src/pkg/http/cookie_test.go
+++ b/src/pkg/http/cookie_test.go
@@ -5,7 +5,6 @@
package http
import (
- "bytes"
"fmt"
"json"
"os"
@@ -15,30 +14,31 @@ import (
)
var writeSetCookiesTests = []struct {
- Cookies []*Cookie
- Raw string
+ Cookie *Cookie
+ Raw string
}{
{
- []*Cookie{
- &Cookie{Name: "cookie-1", Value: "v$1"},
- &Cookie{Name: "cookie-2", Value: "two", MaxAge: 3600},
- &Cookie{Name: "cookie-3", Value: "three", Domain: ".example.com"},
- &Cookie{Name: "cookie-4", Value: "four", Path: "/restricted/"},
- },
- "Set-Cookie: cookie-1=v$1\r\n" +
- "Set-Cookie: cookie-2=two; Max-Age=3600\r\n" +
- "Set-Cookie: cookie-3=three; Domain=.example.com\r\n" +
- "Set-Cookie: cookie-4=four; Path=/restricted/\r\n",
+ &Cookie{Name: "cookie-1", Value: "v$1"},
+ "cookie-1=v$1",
+ },
+ {
+ &Cookie{Name: "cookie-2", Value: "two", MaxAge: 3600},
+ "cookie-2=two; Max-Age=3600",
+ },
+ {
+ &Cookie{Name: "cookie-3", Value: "three", Domain: ".example.com"},
+ "cookie-3=three; Domain=.example.com",
+ },
+ {
+ &Cookie{Name: "cookie-4", Value: "four", Path: "/restricted/"},
+ "cookie-4=four; Path=/restricted/",
},
}
func TestWriteSetCookies(t *testing.T) {
for i, tt := range writeSetCookiesTests {
- var w bytes.Buffer
- writeSetCookies(&w, tt.Cookies)
- seen := string(w.Bytes())
- if seen != tt.Raw {
- t.Errorf("Test %d, expecting:\n%s\nGot:\n%s\n", i, tt.Raw, seen)
+ if g, e := tt.Cookie.String(), tt.Raw; g != e {
+ t.Errorf("Test %d, expecting:\n%s\nGot:\n%s\n", i, e, g)
continue
}
}
@@ -73,7 +73,7 @@ func TestSetCookie(t *testing.T) {
}
}
-var writeCookiesTests = []struct {
+var addCookieTests = []struct {
Cookies []*Cookie
Raw string
}{
@@ -83,7 +83,7 @@ var writeCookiesTests = []struct {
},
{
[]*Cookie{&Cookie{Name: "cookie-1", Value: "v$1"}},
- "Cookie: cookie-1=v$1\r\n",
+ "cookie-1=v$1",
},
{
[]*Cookie{
@@ -91,17 +91,18 @@ var writeCookiesTests = []struct {
&Cookie{Name: "cookie-2", Value: "v$2"},
&Cookie{Name: "cookie-3", Value: "v$3"},
},
- "Cookie: cookie-1=v$1; cookie-2=v$2; cookie-3=v$3\r\n",
+ "cookie-1=v$1; cookie-2=v$2; cookie-3=v$3",
},
}
-func TestWriteCookies(t *testing.T) {
- for i, tt := range writeCookiesTests {
- var w bytes.Buffer
- writeCookies(&w, tt.Cookies)
- seen := string(w.Bytes())
- if seen != tt.Raw {
- t.Errorf("Test %d, expecting:\n%s\nGot:\n%s\n", i, tt.Raw, seen)
+func TestAddCookie(t *testing.T) {
+ for i, tt := range addCookieTests {
+ req, _ := NewRequest("GET", "http://example.com/", nil)
+ for _, c := range tt.Cookies {
+ req.AddCookie(c)
+ }
+ if g := req.Header.Get("Cookie"); g != tt.Raw {
+ t.Errorf("Test %d:\nwant: %s\n got: %s\n", i, tt.Raw, g)
continue
}
}
@@ -140,30 +141,61 @@ func toJSON(v interface{}) string {
func TestReadSetCookies(t *testing.T) {
for i, tt := range readSetCookiesTests {
- c := readSetCookies(tt.Header)
- if !reflect.DeepEqual(c, tt.Cookies) {
- t.Errorf("#%d readSetCookies: have\n%s\nwant\n%s\n", i, toJSON(c), toJSON(tt.Cookies))
- continue
+ for n := 0; n < 2; n++ { // to verify readSetCookies doesn't mutate its input
+ c := readSetCookies(tt.Header)
+ if !reflect.DeepEqual(c, tt.Cookies) {
+ t.Errorf("#%d readSetCookies: have\n%s\nwant\n%s\n", i, toJSON(c), toJSON(tt.Cookies))
+ continue
+ }
}
}
}
var readCookiesTests = []struct {
Header Header
+ Filter string
Cookies []*Cookie
}{
{
- Header{"Cookie": {"Cookie-1=v$1"}},
- []*Cookie{&Cookie{Name: "Cookie-1", Value: "v$1"}},
+ Header{"Cookie": {"Cookie-1=v$1", "c2=v2"}},
+ "",
+ []*Cookie{
+ &Cookie{Name: "Cookie-1", Value: "v$1"},
+ &Cookie{Name: "c2", Value: "v2"},
+ },
+ },
+ {
+ Header{"Cookie": {"Cookie-1=v$1", "c2=v2"}},
+ "c2",
+ []*Cookie{
+ &Cookie{Name: "c2", Value: "v2"},
+ },
+ },
+ {
+ Header{"Cookie": {"Cookie-1=v$1; c2=v2"}},
+ "",
+ []*Cookie{
+ &Cookie{Name: "Cookie-1", Value: "v$1"},
+ &Cookie{Name: "c2", Value: "v2"},
+ },
+ },
+ {
+ Header{"Cookie": {"Cookie-1=v$1; c2=v2"}},
+ "c2",
+ []*Cookie{
+ &Cookie{Name: "c2", Value: "v2"},
+ },
},
}
func TestReadCookies(t *testing.T) {
for i, tt := range readCookiesTests {
- c := readCookies(tt.Header)
- if !reflect.DeepEqual(c, tt.Cookies) {
- t.Errorf("#%d readCookies: have\n%s\nwant\n%s\n", i, toJSON(c), toJSON(tt.Cookies))
- continue
+ for n := 0; n < 2; n++ { // to verify readCookies doesn't mutate its input
+ c := readCookies(tt.Header, tt.Filter)
+ if !reflect.DeepEqual(c, tt.Cookies) {
+ t.Errorf("#%d readCookies:\nhave: %s\nwant: %s\n", i, toJSON(c), toJSON(tt.Cookies))
+ continue
+ }
}
}
}
diff --git a/src/pkg/http/fs.go b/src/pkg/http/fs.go
index 28a0c51ef..56512980c 100644
--- a/src/pkg/http/fs.go
+++ b/src/pkg/http/fs.go
@@ -157,7 +157,7 @@ func serveFile(w ResponseWriter, r *Request, name string, redirect bool) {
// TODO(adg): handle multiple ranges
ranges, err := parseRange(r.Header.Get("Range"), size)
if err == nil && len(ranges) > 1 {
- err = os.ErrorString("multiple ranges not supported")
+ err = os.NewError("multiple ranges not supported")
}
if err != nil {
Error(w, err.String(), StatusRequestedRangeNotSatisfiable)
diff --git a/src/pkg/http/header.go b/src/pkg/http/header.go
index 95140b01f..95a25a814 100644
--- a/src/pkg/http/header.go
+++ b/src/pkg/http/header.go
@@ -62,9 +62,6 @@ func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) os.Error {
v = strings.Replace(v, "\n", " ", -1)
v = strings.Replace(v, "\r", " ", -1)
v = strings.TrimSpace(v)
- if v == "" {
- continue
- }
if _, err := fmt.Fprintf(w, "%s: %s\r\n", k, v); err != nil {
return err
}
diff --git a/src/pkg/http/header_test.go b/src/pkg/http/header_test.go
index 7e24cb069..ccdee8a97 100644
--- a/src/pkg/http/header_test.go
+++ b/src/pkg/http/header_test.go
@@ -57,6 +57,16 @@ var headerWriteTests = []struct {
map[string]bool{"Content-Length": true, "Expires": true, "Content-Encoding": true},
"",
},
+ {
+ Header{
+ "Nil": nil,
+ "Empty": {},
+ "Blank": {""},
+ "Double-Blank": {"", ""},
+ },
+ nil,
+ "Blank: \r\nDouble-Blank: \r\nDouble-Blank: \r\n",
+ },
}
func TestHeaderWrite(t *testing.T) {
diff --git a/src/pkg/http/readrequest_test.go b/src/pkg/http/readrequest_test.go
index d93e573f5..0b92b7942 100644
--- a/src/pkg/http/readrequest_test.go
+++ b/src/pkg/http/readrequest_test.go
@@ -58,12 +58,11 @@ var reqTests = []reqTest{
"Keep-Alive": {"300"},
"Proxy-Connection": {"keep-alive"},
"Content-Length": {"7"},
+ "User-Agent": {"Fake"},
},
Close: false,
ContentLength: 7,
Host: "www.techcrunch.com",
- Referer: "",
- UserAgent: "Fake",
Form: Values{},
},
@@ -97,8 +96,6 @@ var reqTests = []reqTest{
Close: false,
ContentLength: -1,
Host: "test",
- Referer: "",
- UserAgent: "",
Form: Values{},
},
diff --git a/src/pkg/http/request.go b/src/pkg/http/request.go
index bdc3a7e4f..183a35c71 100644
--- a/src/pkg/http/request.go
+++ b/src/pkg/http/request.go
@@ -35,13 +35,15 @@ const (
// ErrMissingFile is returned by FormFile when the provided file field name
// is either not present in the request or not a file field.
-var ErrMissingFile = os.ErrorString("http: no such file")
+var ErrMissingFile = os.NewError("http: no such file")
// HTTP request parsing errors.
type ProtocolError struct {
- os.ErrorString
+ ErrorString string
}
+func (err *ProtocolError) String() string { return err.ErrorString }
+
var (
ErrLineTooLong = &ProtocolError{"header line too long"}
ErrHeaderTooLong = &ProtocolError{"header too long"}
@@ -60,10 +62,10 @@ type badStringError struct {
func (e *badStringError) String() string { return fmt.Sprintf("%s %q", e.what, e.str) }
-var reqExcludeHeader = map[string]bool{
+// Headers that Request.Write handles itself and should be skipped.
+var reqWriteExcludeHeader = map[string]bool{
"Host": true,
"User-Agent": true,
- "Referer": true,
"Content-Length": true,
"Transfer-Encoding": true,
"Trailer": true,
@@ -102,9 +104,6 @@ type Request struct {
// following a hyphen uppercase and the rest lowercase.
Header Header
- // Cookie records the HTTP cookies sent with the request.
- Cookie []*Cookie
-
// The message body.
Body io.ReadCloser
@@ -125,21 +124,6 @@ type Request struct {
// or the host name given in the URL itself.
Host string
- // The referring URL, if sent in the request.
- //
- // Referer is misspelled as in the request itself,
- // a mistake from the earliest days of HTTP.
- // This value can also be fetched from the Header map
- // as Header["Referer"]; the benefit of making it
- // available as a structure field is that the compiler
- // can diagnose programs that use the alternate
- // (correct English) spelling req.Referrer but cannot
- // diagnose programs that use Header["Referrer"].
- Referer string
-
- // The User-Agent: header string, if sent in the request.
- UserAgent string
-
// The parsed form. Only available after ParseForm is called.
Form Values
@@ -176,6 +160,52 @@ func (r *Request) ProtoAtLeast(major, minor int) bool {
r.ProtoMajor == major && r.ProtoMinor >= minor
}
+// UserAgent returns the client's User-Agent, if sent in the request.
+func (r *Request) UserAgent() string {
+ return r.Header.Get("User-Agent")
+}
+
+// Cookies parses and returns the HTTP cookies sent with the request.
+func (r *Request) Cookies() []*Cookie {
+ return readCookies(r.Header, "")
+}
+
+var ErrNoCookie = os.NewError("http: named cookied not present")
+
+// Cookie returns the named cookie provided in the request or
+// ErrNoCookie if not found.
+func (r *Request) Cookie(name string) (*Cookie, os.Error) {
+ for _, c := range readCookies(r.Header, name) {
+ return c, nil
+ }
+ return nil, ErrNoCookie
+}
+
+// AddCookie adds a cookie to the request. Per RFC 6265 section 5.4,
+// AddCookie does not attach more than one Cookie header field. That
+// means all cookies, if any, are written into the same line,
+// separated by semicolon.
+func (r *Request) AddCookie(c *Cookie) {
+ s := fmt.Sprintf("%s=%s", sanitizeName(c.Name), sanitizeValue(c.Value))
+ if c := r.Header.Get("Cookie"); c != "" {
+ r.Header.Set("Cookie", c+"; "+s)
+ } else {
+ r.Header.Set("Cookie", s)
+ }
+}
+
+// Referer returns the referring URL, if sent in the request.
+//
+// Referer is misspelled as in the request itself, a mistake from the
+// earliest days of HTTP. This value can also be fetched from the
+// Header map as Header["Referer"]; the benefit of making it available
+// as a method is that the compiler can diagnose programs that use the
+// alternate (correct English) spelling req.Referrer() but cannot
+// diagnose programs that use Header["Referrer"].
+func (r *Request) Referer() string {
+ return r.Header.Get("Referer")
+}
+
// multipartByReader is a sentinel value.
// Its presence in Request.MultipartForm indicates that parsing of the request
// body has been handed off to a MultipartReader instead of ParseMultipartFrom.
@@ -188,7 +218,7 @@ var multipartByReader = &multipart.Form{
// multipart/form-data POST request, else returns nil and an error.
// Use this function instead of ParseMultipartForm to
// process the request body as a stream.
-func (r *Request) MultipartReader() (multipart.Reader, os.Error) {
+func (r *Request) MultipartReader() (*multipart.Reader, os.Error) {
if r.MultipartForm == multipartByReader {
return nil, os.NewError("http: MultipartReader called twice")
}
@@ -199,7 +229,7 @@ func (r *Request) MultipartReader() (multipart.Reader, os.Error) {
return r.multipartReader()
}
-func (r *Request) multipartReader() (multipart.Reader, os.Error) {
+func (r *Request) multipartReader() (*multipart.Reader, os.Error) {
v := r.Header.Get("Content-Type")
if v == "" {
return nil, ErrNotMultipart
@@ -230,10 +260,7 @@ const defaultUserAgent = "Go http package"
// Host
// RawURL, if non-empty, or else URL
// Method (defaults to "GET")
-// UserAgent (defaults to defaultUserAgent)
-// Referer
-// Header (only keys not already in this list)
-// Cookie
+// Header
// ContentLength
// TransferEncoding
// Body
@@ -277,13 +304,22 @@ func (req *Request) write(w io.Writer, usingProxy bool) os.Error {
}
}
- fmt.Fprintf(w, "%s %s HTTP/1.1\r\n", valueOrDefault(req.Method, "GET"), uri)
+ bw := bufio.NewWriter(w)
+ fmt.Fprintf(bw, "%s %s HTTP/1.1\r\n", valueOrDefault(req.Method, "GET"), uri)
// Header lines
- fmt.Fprintf(w, "Host: %s\r\n", host)
- fmt.Fprintf(w, "User-Agent: %s\r\n", valueOrDefault(req.UserAgent, defaultUserAgent))
- if req.Referer != "" {
- fmt.Fprintf(w, "Referer: %s\r\n", req.Referer)
+ fmt.Fprintf(bw, "Host: %s\r\n", host)
+
+ // Use the defaultUserAgent unless the Header contains one, which
+ // may be blank to not send the header.
+ userAgent := defaultUserAgent
+ if req.Header != nil {
+ if ua := req.Header["User-Agent"]; len(ua) > 0 {
+ userAgent = ua[0]
+ }
+ }
+ if userAgent != "" {
+ fmt.Fprintf(bw, "User-Agent: %s\r\n", userAgent)
}
// Process Body,ContentLength,Close,Trailer
@@ -291,35 +327,25 @@ func (req *Request) write(w io.Writer, usingProxy bool) os.Error {
if err != nil {
return err
}
- err = tw.WriteHeader(w)
+ err = tw.WriteHeader(bw)
if err != nil {
return err
}
// TODO: split long values? (If so, should share code with Conn.Write)
- // TODO: if Header includes values for Host, User-Agent, or Referer, this
- // may conflict with the User-Agent or Referer headers we add manually.
- // One solution would be to remove the Host, UserAgent, and Referer fields
- // from Request, and introduce Request methods along the lines of
- // Response.{GetHeader,AddHeader} and string constants for "Host",
- // "User-Agent" and "Referer".
- err = req.Header.WriteSubset(w, reqExcludeHeader)
+ err = req.Header.WriteSubset(bw, reqWriteExcludeHeader)
if err != nil {
return err
}
- if err = writeCookies(w, req.Cookie); err != nil {
- return err
- }
-
- io.WriteString(w, "\r\n")
+ io.WriteString(bw, "\r\n")
// Write body and trailer
- err = tw.WriteBody(w)
+ err = tw.WriteBody(bw)
if err != nil {
return err
}
-
+ bw.Flush()
return nil
}
@@ -559,13 +585,6 @@ func ReadRequest(b *bufio.Reader) (req *Request, err os.Error) {
fixPragmaCacheControl(req.Header)
- // Pull out useful fields as a convenience to clients.
- req.Referer = req.Header.Get("Referer")
- req.Header.Del("Referer")
-
- req.UserAgent = req.Header.Get("User-Agent")
- req.Header.Del("User-Agent")
-
// TODO: Parse specific header values:
// Accept
// Accept-Encoding
@@ -597,8 +616,6 @@ func ReadRequest(b *bufio.Reader) (req *Request, err os.Error) {
return nil, err
}
- req.Cookie = readCookies(req.Header)
-
return req, nil
}
@@ -690,7 +707,7 @@ func (r *Request) ParseForm() (err os.Error) {
}
if r.Method == "POST" {
if r.Body == nil {
- return os.ErrorString("missing form body")
+ return os.NewError("missing form body")
}
ct := r.Header.Get("Content-Type")
switch strings.Split(ct, ";", 2)[0] {
diff --git a/src/pkg/http/requestwrite_test.go b/src/pkg/http/requestwrite_test.go
index 98fbcf459..43ad5252d 100644
--- a/src/pkg/http/requestwrite_test.go
+++ b/src/pkg/http/requestwrite_test.go
@@ -47,13 +47,12 @@ var reqWriteTests = []reqWriteTest{
"Accept-Language": {"en-us,en;q=0.5"},
"Keep-Alive": {"300"},
"Proxy-Connection": {"keep-alive"},
+ "User-Agent": {"Fake"},
},
- Body: nil,
- Close: false,
- Host: "www.techcrunch.com",
- Referer: "",
- UserAgent: "Fake",
- Form: map[string][]string{},
+ Body: nil,
+ Close: false,
+ Host: "www.techcrunch.com",
+ Form: map[string][]string{},
},
nil,
@@ -233,6 +232,9 @@ func TestRequestWrite(t *testing.T) {
if tt.Body != nil {
tt.Req.Body = ioutil.NopCloser(bytes.NewBuffer(tt.Body))
}
+ if tt.Req.Header == nil {
+ tt.Req.Header = make(Header)
+ }
var braw bytes.Buffer
err := tt.Req.Write(&braw)
if err != nil {
diff --git a/src/pkg/http/response.go b/src/pkg/http/response.go
index 42e60c1f6..6c0c441a9 100644
--- a/src/pkg/http/response.go
+++ b/src/pkg/http/response.go
@@ -40,9 +40,6 @@ type Response struct {
// Keys in the map are canonicalized (see CanonicalHeaderKey).
Header Header
- // SetCookie records the Set-Cookie requests sent with the response.
- SetCookie []*Cookie
-
// Body represents the response body.
Body io.ReadCloser
@@ -71,6 +68,11 @@ type Response struct {
Request *Request
}
+// Cookies parses and returns the cookies set in the Set-Cookie headers.
+func (r *Response) Cookies() []*Cookie {
+ return readSetCookies(r.Header)
+}
+
// ReadResponse reads and returns an HTTP response from r. The
// req parameter specifies the Request that corresponds to
// this Response. Clients must call resp.Body.Close when finished
@@ -127,8 +129,6 @@ func ReadResponse(r *bufio.Reader, req *Request) (resp *Response, err os.Error)
return nil, err
}
- resp.SetCookie = readSetCookies(resp.Header)
-
return resp, nil
}
@@ -200,10 +200,6 @@ func (resp *Response) Write(w io.Writer) os.Error {
return err
}
- if err = writeSetCookies(w, resp.SetCookie); err != nil {
- return err
- }
-
// End-of-header
io.WriteString(w, "\r\n")
diff --git a/src/pkg/http/reverseproxy.go b/src/pkg/http/reverseproxy.go
index 9a9e21599..e4ce1e34c 100644
--- a/src/pkg/http/reverseproxy.go
+++ b/src/pkg/http/reverseproxy.go
@@ -92,10 +92,6 @@ func (p *ReverseProxy) ServeHTTP(rw ResponseWriter, req *Request) {
}
}
- for _, cookie := range res.SetCookie {
- SetCookie(rw, cookie)
- }
-
rw.WriteHeader(res.StatusCode)
if res.Body != nil {
diff --git a/src/pkg/http/reverseproxy_test.go b/src/pkg/http/reverseproxy_test.go
index d7bcde90d..bc0861481 100644
--- a/src/pkg/http/reverseproxy_test.go
+++ b/src/pkg/http/reverseproxy_test.go
@@ -49,10 +49,10 @@ func TestReverseProxy(t *testing.T) {
if g, e := res.Header.Get("X-Foo"), "bar"; g != e {
t.Errorf("got X-Foo %q; expected %q", g, e)
}
- if g, e := len(res.SetCookie), 1; g != e {
+ if g, e := len(res.Header["Set-Cookie"]), 1; g != e {
t.Fatalf("got %d SetCookies, want %d", g, e)
}
- if cookie := res.SetCookie[0]; cookie.Name != "flavor" {
+ if cookie := res.Cookies()[0]; cookie.Name != "flavor" {
t.Errorf("unexpected cookie %q", cookie.Name)
}
bodyBytes, _ := ioutil.ReadAll(res.Body)
diff --git a/src/pkg/http/serve_test.go b/src/pkg/http/serve_test.go
index dc4594a79..40de54747 100644
--- a/src/pkg/http/serve_test.go
+++ b/src/pkg/http/serve_test.go
@@ -781,6 +781,21 @@ func TestHandlerPanic(t *testing.T) {
}
}
+func TestNoDate(t *testing.T) {
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Header()["Date"] = nil
+ }))
+ defer ts.Close()
+ res, err := Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ _, present := res.Header["Date"]
+ if present {
+ t.Fatalf("Expected no Date header; got %v", res.Header["Date"])
+ }
+}
+
type errorListener struct {
errs []os.Error
}
diff --git a/src/pkg/http/server.go b/src/pkg/http/server.go
index d4638f127..7f1b8a2bc 100644
--- a/src/pkg/http/server.go
+++ b/src/pkg/http/server.go
@@ -20,7 +20,7 @@ import (
"net"
"os"
"path"
- "runtime"
+ "runtime/debug"
"strconv"
"strings"
"sync"
@@ -254,7 +254,7 @@ func (w *response) WriteHeader(code int) {
}
}
- if w.header.Get("Date") == "" {
+ if _, ok := w.header["Date"]; !ok {
w.Header().Set("Date", time.UTC().Format(TimeFormat))
}
@@ -405,7 +405,7 @@ func errorKludge(w *response) {
// Is it a broken browser?
var msg string
- switch agent := w.req.UserAgent; {
+ switch agent := w.req.UserAgent(); {
case strings.Contains(agent, "MSIE"):
msg = "Internet Explorer"
case strings.Contains(agent, "Chrome/"):
@@ -490,23 +490,9 @@ func (c *conn) serve() {
}
c.rwc.Close()
- // TODO(rsc,bradfitz): this is boilerplate. move it to runtime.Stack()
var buf bytes.Buffer
fmt.Fprintf(&buf, "http: panic serving %v: %v\n", c.remoteAddr, err)
- for i := 1; i < 20; i++ {
- pc, file, line, ok := runtime.Caller(i)
- if !ok {
- break
- }
- var name string
- f := runtime.FuncForPC(pc)
- if f != nil {
- name = f.Name()
- } else {
- name = fmt.Sprintf("%#x", pc)
- }
- fmt.Fprintf(&buf, " %s %s:%d\n", name, file, line)
- }
+ buf.Write(debug.Stack())
log.Print(buf.String())
}()
@@ -584,7 +570,7 @@ func (w *response) Hijack() (rwc net.Conn, buf *bufio.ReadWriter, err os.Error)
// Handler object that calls f.
type HandlerFunc func(ResponseWriter, *Request)
-// ServeHTTP calls f(w, req).
+// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
@@ -922,7 +908,9 @@ func ListenAndServe(addr string, handler Handler) os.Error {
// ListenAndServeTLS acts identically to ListenAndServe, except that it
// expects HTTPS connections. Additionally, files containing a certificate and
-// matching private key for the server must be provided.
+// matching private key for the server must be provided. If the certificate
+// is signed by a certificate authority, the certFile should be the concatenation
+// of the server's certificate followed by the CA's certificate.
//
// A trivial example server is:
//
@@ -947,6 +935,24 @@ func ListenAndServe(addr string, handler Handler) os.Error {
//
// One can use generate_cert.go in crypto/tls to generate cert.pem and key.pem.
func ListenAndServeTLS(addr string, certFile string, keyFile string, handler Handler) os.Error {
+ server := &Server{Addr: addr, Handler: handler}
+ return server.ListenAndServeTLS(certFile, keyFile)
+}
+
+// ListenAndServeTLS listens on the TCP network address srv.Addr and
+// then calls Serve to handle requests on incoming TLS connections.
+//
+// Filenames containing a certificate and matching private key for
+// the server must be provided. If the certificate is signed by a
+// certificate authority, the certFile should be the concatenation
+// 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) os.Error {
+ addr := s.Addr
+ if addr == "" {
+ addr = ":https"
+ }
config := &tls.Config{
Rand: rand.Reader,
Time: time.Seconds,
@@ -966,7 +972,7 @@ func ListenAndServeTLS(addr string, certFile string, keyFile string, handler Han
}
tlsListener := tls.NewListener(conn, config)
- return Serve(tlsListener, handler)
+ return s.Serve(tlsListener)
}
// TimeoutHandler returns a Handler that runs h with the given time limit.
diff --git a/src/pkg/http/spdy/read.go b/src/pkg/http/spdy/read.go
index 159dbc578..8adec7bd4 100644
--- a/src/pkg/http/spdy/read.go
+++ b/src/pkg/http/spdy/read.go
@@ -80,7 +80,7 @@ func (frame *HeadersFrame) read(h ControlFrameHeader, f *Framer) os.Error {
func newControlFrame(frameType ControlFrameType) (controlFrame, os.Error) {
ctor, ok := cframeCtor[frameType]
if !ok {
- return nil, InvalidControlFrame
+ return nil, &Error{Err: InvalidControlFrame}
}
return ctor(), nil
}
@@ -97,30 +97,12 @@ var cframeCtor = map[ControlFrameType]func() controlFrame{
// TODO(willchan): Add TypeWindowUpdate
}
-type corkedReader struct {
- r io.Reader
- ch chan int
- n int
-}
-
-func (cr *corkedReader) Read(p []byte) (int, os.Error) {
- if cr.n == 0 {
- cr.n = <-cr.ch
- }
- if len(p) > cr.n {
- p = p[:cr.n]
- }
- n, err := cr.r.Read(p)
- cr.n -= n
- return n, err
-}
-
-func (f *Framer) uncorkHeaderDecompressor(payloadSize int) os.Error {
+func (f *Framer) uncorkHeaderDecompressor(payloadSize int64) os.Error {
if f.headerDecompressor != nil {
- f.headerReader.ch <- payloadSize
+ f.headerReader.N = payloadSize
return nil
}
- f.headerReader = corkedReader{r: f.r, ch: make(chan int, 1), n: payloadSize}
+ f.headerReader = io.LimitedReader{R: f.r, N: payloadSize}
decompressor, err := zlib.NewReaderDict(&f.headerReader, []byte(HeaderDictionary))
if err != nil {
return err
@@ -161,11 +143,12 @@ func (f *Framer) parseControlFrame(version uint16, frameType ControlFrameType) (
return cframe, nil
}
-func parseHeaderValueBlock(r io.Reader) (http.Header, os.Error) {
+func parseHeaderValueBlock(r io.Reader, streamId uint32) (http.Header, os.Error) {
var numHeaders uint16
if err := binary.Read(r, binary.BigEndian, &numHeaders); err != nil {
return nil, err
}
+ var e os.Error
h := make(http.Header, int(numHeaders))
for i := 0; i < int(numHeaders); i++ {
var length uint16
@@ -178,10 +161,11 @@ func parseHeaderValueBlock(r io.Reader) (http.Header, os.Error) {
}
name := string(nameBytes)
if name != strings.ToLower(name) {
- return nil, UnlowercasedHeaderName
+ e = &Error{UnlowercasedHeaderName, streamId}
+ name = strings.ToLower(name)
}
if h[name] != nil {
- return nil, DuplicateHeaders
+ e = &Error{DuplicateHeaders, streamId}
}
if err := binary.Read(r, binary.BigEndian, &length); err != nil {
return nil, err
@@ -195,6 +179,9 @@ func parseHeaderValueBlock(r io.Reader) (http.Header, os.Error) {
h.Add(name, v)
}
}
+ if e != nil {
+ return h, e
+ }
return h, nil
}
@@ -214,14 +201,25 @@ func (f *Framer) readSynStreamFrame(h ControlFrameHeader, frame *SynStreamFrame)
reader := f.r
if !f.headerCompressionDisabled {
- f.uncorkHeaderDecompressor(int(h.length - 10))
+ f.uncorkHeaderDecompressor(int64(h.length - 10))
reader = f.headerDecompressor
}
- frame.Headers, err = parseHeaderValueBlock(reader)
+ frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId)
+ if !f.headerCompressionDisabled && ((err == os.EOF && f.headerReader.N == 0) || f.headerReader.N != 0) {
+ err = &Error{WrongCompressedPayloadSize, 0}
+ }
if err != nil {
return err
}
+ // Remove this condition when we bump Version to 3.
+ if Version >= 3 {
+ for h, _ := range frame.Headers {
+ if invalidReqHeaders[h] {
+ return &Error{InvalidHeaderPresent, frame.StreamId}
+ }
+ }
+ }
return nil
}
@@ -237,13 +235,24 @@ func (f *Framer) readSynReplyFrame(h ControlFrameHeader, frame *SynReplyFrame) o
}
reader := f.r
if !f.headerCompressionDisabled {
- f.uncorkHeaderDecompressor(int(h.length - 6))
+ f.uncorkHeaderDecompressor(int64(h.length - 6))
reader = f.headerDecompressor
}
- frame.Headers, err = parseHeaderValueBlock(reader)
+ frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId)
+ if !f.headerCompressionDisabled && ((err == os.EOF && f.headerReader.N == 0) || f.headerReader.N != 0) {
+ err = &Error{WrongCompressedPayloadSize, 0}
+ }
if err != nil {
return err
}
+ // Remove this condition when we bump Version to 3.
+ if Version >= 3 {
+ for h, _ := range frame.Headers {
+ if invalidRespHeaders[h] {
+ return &Error{InvalidHeaderPresent, frame.StreamId}
+ }
+ }
+ }
return nil
}
@@ -259,13 +268,31 @@ func (f *Framer) readHeadersFrame(h ControlFrameHeader, frame *HeadersFrame) os.
}
reader := f.r
if !f.headerCompressionDisabled {
- f.uncorkHeaderDecompressor(int(h.length - 6))
+ f.uncorkHeaderDecompressor(int64(h.length - 6))
reader = f.headerDecompressor
}
- frame.Headers, err = parseHeaderValueBlock(reader)
+ frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId)
+ if !f.headerCompressionDisabled && ((err == os.EOF && f.headerReader.N == 0) || f.headerReader.N != 0) {
+ err = &Error{WrongCompressedPayloadSize, 0}
+ }
if err != nil {
return err
}
+
+ // Remove this condition when we bump Version to 3.
+ if Version >= 3 {
+ var invalidHeaders map[string]bool
+ if frame.StreamId%2 == 0 {
+ invalidHeaders = invalidReqHeaders
+ } else {
+ invalidHeaders = invalidRespHeaders
+ }
+ for h, _ := range frame.Headers {
+ if invalidHeaders[h] {
+ return &Error{InvalidHeaderPresent, frame.StreamId}
+ }
+ }
+ }
return nil
}
@@ -279,7 +306,6 @@ func (f *Framer) parseDataFrame(streamId uint32) (*DataFrame, os.Error) {
frame.Flags = DataFlags(length >> 24)
length &= 0xffffff
frame.Data = make([]byte, length)
- // TODO(willchan): Support compressed data frames.
if _, err := io.ReadFull(f.r, frame.Data); err != nil {
return nil, err
}
diff --git a/src/pkg/http/spdy/spdy_test.go b/src/pkg/http/spdy/spdy_test.go
index 9100e1ea8..cb91e0286 100644
--- a/src/pkg/http/spdy/spdy_test.go
+++ b/src/pkg/http/spdy/spdy_test.go
@@ -21,7 +21,8 @@ func TestHeaderParsing(t *testing.T) {
var headerValueBlockBuf bytes.Buffer
writeHeaderValueBlock(&headerValueBlockBuf, headers)
- newHeaders, err := parseHeaderValueBlock(&headerValueBlockBuf)
+ const bogusStreamId = 1
+ newHeaders, err := parseHeaderValueBlock(&headerValueBlockBuf, bogusStreamId)
if err != nil {
t.Fatal("parseHeaderValueBlock:", err)
}
diff --git a/src/pkg/http/spdy/types.go b/src/pkg/http/spdy/types.go
index 5a665f04f..41cafb174 100644
--- a/src/pkg/http/spdy/types.go
+++ b/src/pkg/http/spdy/types.go
@@ -10,7 +10,6 @@ import (
"http"
"io"
"os"
- "strconv"
)
// Data Frame Format
@@ -302,33 +301,41 @@ const HeaderDictionary = "optionsgetheadpostputdeletetrace" +
"chunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplication/xhtmltext/plainpublicmax-age" +
"charset=iso-8859-1utf-8gzipdeflateHTTP/1.1statusversionurl\x00"
-type FramerError int
+// A SPDY specific error.
+type ErrorCode string
const (
- Internal FramerError = iota
- InvalidControlFrame
- UnlowercasedHeaderName
- DuplicateHeaders
- UnknownFrameType
- InvalidDataFrame
+ UnlowercasedHeaderName ErrorCode = "header was not lowercased"
+ DuplicateHeaders ErrorCode = "multiple headers with same name"
+ WrongCompressedPayloadSize ErrorCode = "compressed payload size was incorrect"
+ UnknownFrameType ErrorCode = "unknown frame type"
+ InvalidControlFrame ErrorCode = "invalid control frame"
+ InvalidDataFrame ErrorCode = "invalid data frame"
+ InvalidHeaderPresent ErrorCode = "frame contained invalid header"
)
-func (e FramerError) String() string {
- switch e {
- case Internal:
- return "Internal"
- case InvalidControlFrame:
- return "InvalidControlFrame"
- case UnlowercasedHeaderName:
- return "UnlowercasedHeaderName"
- case DuplicateHeaders:
- return "DuplicateHeaders"
- case UnknownFrameType:
- return "UnknownFrameType"
- case InvalidDataFrame:
- return "InvalidDataFrame"
- }
- return "Error(" + strconv.Itoa(int(e)) + ")"
+// Error contains both the type of error and additional values. StreamId is 0
+// if Error is not associated with a stream.
+type Error struct {
+ Err ErrorCode
+ StreamId uint32
+}
+
+func (e *Error) String() string {
+ return string(e.Err)
+}
+
+var invalidReqHeaders = map[string]bool{
+ "Connection": true,
+ "Keep-Alive": true,
+ "Proxy-Connection": true,
+ "Transfer-Encoding": true,
+}
+
+var invalidRespHeaders = map[string]bool{
+ "Connection": true,
+ "Keep-Alive": true,
+ "Transfer-Encoding": true,
}
// Framer handles serializing/deserializing SPDY frames, including compressing/
@@ -339,7 +346,7 @@ type Framer struct {
headerBuf *bytes.Buffer
headerCompressor *zlib.Writer
r io.Reader
- headerReader corkedReader
+ headerReader io.LimitedReader
headerDecompressor io.ReadCloser
}
diff --git a/src/pkg/http/spdy/write.go b/src/pkg/http/spdy/write.go
index aa1679f1b..7d40bbe9f 100644
--- a/src/pkg/http/spdy/write.go
+++ b/src/pkg/http/spdy/write.go
@@ -267,10 +267,9 @@ func (f *Framer) writeHeadersFrame(frame *HeadersFrame) (err os.Error) {
func (f *Framer) writeDataFrame(frame *DataFrame) (err os.Error) {
// Validate DataFrame
if frame.StreamId&0x80000000 != 0 || len(frame.Data) >= 0x0f000000 {
- return InvalidDataFrame
+ return &Error{InvalidDataFrame, frame.StreamId}
}
- // TODO(willchan): Support data compression.
// Serialize frame to Writer
if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
return
diff --git a/src/pkg/http/transport.go b/src/pkg/http/transport.go
index c907d85fd..9ad159010 100644
--- a/src/pkg/http/transport.go
+++ b/src/pkg/http/transport.go
@@ -76,12 +76,12 @@ func ProxyFromEnvironment(req *Request) (*URL, os.Error) {
}
proxyURL, err := ParseRequestURL(proxy)
if err != nil {
- return nil, os.ErrorString("invalid proxy address")
+ return nil, os.NewError("invalid proxy address")
}
if proxyURL.Host == "" {
proxyURL, err = ParseRequestURL("http://" + proxy)
if err != nil {
- return nil, os.ErrorString("invalid proxy address")
+ return nil, os.NewError("invalid proxy address")
}
}
return proxyURL, nil
@@ -331,7 +331,7 @@ func (t *Transport) getConn(cm *connectMethod) (*persistConn, os.Error) {
if resp.StatusCode != 200 {
f := strings.Split(resp.Status, " ", 2)
conn.Close()
- return nil, os.ErrorString(f[1])
+ return nil, os.NewError(f[1])
}
}
diff --git a/src/pkg/http/url.go b/src/pkg/http/url.go
index 05b1662d3..beb0b8200 100644
--- a/src/pkg/http/url.go
+++ b/src/pkg/http/url.go
@@ -299,7 +299,7 @@ func getscheme(rawurl string) (scheme, path string, err os.Error) {
}
case c == ':':
if i == 0 {
- return "", "", os.ErrorString("missing protocol scheme")
+ return "", "", os.NewError("missing protocol scheme")
}
return rawurl[0:i], rawurl[i+1:], nil
default:
@@ -348,8 +348,13 @@ func ParseRequestURL(rawurl string) (url *URL, err os.Error) {
// in which case only absolute URLs or path-absolute relative URLs are allowed.
// If viaRequest is false, all forms of relative URLs are allowed.
func parseURL(rawurl string, viaRequest bool) (url *URL, err os.Error) {
+ var (
+ leadingSlash bool
+ path string
+ )
+
if rawurl == "" {
- err = os.ErrorString("empty url")
+ err = os.NewError("empty url")
goto Error
}
url = new(URL)
@@ -357,12 +362,10 @@ func parseURL(rawurl string, viaRequest bool) (url *URL, err os.Error) {
// Split off possible leading "http:", "mailto:", etc.
// Cannot contain escaped characters.
- var path string
if url.Scheme, path, err = getscheme(rawurl); err != nil {
goto Error
}
-
- leadingSlash := strings.HasPrefix(path, "/")
+ leadingSlash = strings.HasPrefix(path, "/")
if url.Scheme != "" && !leadingSlash {
// RFC 2396:
@@ -377,7 +380,7 @@ func parseURL(rawurl string, viaRequest bool) (url *URL, err os.Error) {
url.OpaquePath = true
} else {
if viaRequest && !leadingSlash {
- err = os.ErrorString("invalid URI for request")
+ err = os.NewError("invalid URI for request")
goto Error
}
@@ -411,7 +414,7 @@ func parseURL(rawurl string, viaRequest bool) (url *URL, err os.Error) {
if strings.Contains(rawHost, "%") {
// Host cannot contain escaped characters.
- err = os.ErrorString("hexadecimal escape in host")
+ err = os.NewError("hexadecimal escape in host")
goto Error
}
url.Host = rawHost
diff --git a/src/pkg/image/draw/draw.go b/src/pkg/image/draw/draw.go
index 618fb4aa6..0ab7b59ab 100644
--- a/src/pkg/image/draw/draw.go
+++ b/src/pkg/image/draw/draw.go
@@ -34,9 +34,9 @@ type Image interface {
Set(x, y int, c image.Color)
}
-// Draw calls DrawMask with a nil mask and an Over op.
-func Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point) {
- DrawMask(dst, r, src, sp, nil, image.ZP, Over)
+// Draw calls DrawMask with a nil mask.
+func Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point, op Op) {
+ DrawMask(dst, r, src, sp, nil, image.ZP, op)
}
// clip clips r against each image's bounds (after translating into the
diff --git a/src/pkg/image/draw/draw_test.go b/src/pkg/image/draw/draw_test.go
index 37d630353..6db567231 100644
--- a/src/pkg/image/draw/draw_test.go
+++ b/src/pkg/image/draw/draw_test.go
@@ -271,7 +271,7 @@ func TestNonZeroSrcPt(t *testing.T) {
b.Set(1, 0, image.RGBAColor{0, 0, 5, 5})
b.Set(0, 1, image.RGBAColor{0, 5, 0, 5})
b.Set(1, 1, image.RGBAColor{5, 0, 0, 5})
- Draw(a, image.Rect(0, 0, 1, 1), b, image.Pt(1, 1))
+ Draw(a, image.Rect(0, 0, 1, 1), b, image.Pt(1, 1), Over)
if !eq(image.RGBAColor{5, 0, 0, 5}, a.At(0, 0)) {
t.Errorf("non-zero src pt: want %v got %v", image.RGBAColor{5, 0, 0, 5}, a.At(0, 0))
}
diff --git a/src/pkg/image/gif/reader.go b/src/pkg/image/gif/reader.go
index 26c013b9a..98ac01cca 100644
--- a/src/pkg/image/gif/reader.go
+++ b/src/pkg/image/gif/reader.go
@@ -186,7 +186,7 @@ Loop:
return err
}
if c != 0 {
- return os.ErrorString("gif: extra data after image")
+ return os.NewError("gif: extra data after image")
}
// Undo the interlacing if necessary.
diff --git a/src/pkg/image/image_test.go b/src/pkg/image/image_test.go
index 17e314795..f167f7f28 100644
--- a/src/pkg/image/image_test.go
+++ b/src/pkg/image/image_test.go
@@ -8,6 +8,12 @@ import (
"testing"
)
+type image interface {
+ Image
+ Set(int, int, Color)
+ SubImage(Rectangle) Image
+}
+
func cmp(t *testing.T, cm ColorModel, c0, c1 Color) bool {
r0, g0, b0, a0 := cm.Convert(c0).RGBA()
r1, g1, b1, a1 := cm.Convert(c1).RGBA()
@@ -15,12 +21,7 @@ func cmp(t *testing.T, cm ColorModel, c0, c1 Color) bool {
}
func TestImage(t *testing.T) {
- type buffered interface {
- Image
- Set(int, int, Color)
- SubImage(Rectangle) Image
- }
- testImage := []Image{
+ testImage := []image{
NewRGBA(10, 10),
NewRGBA64(10, 10),
NewNRGBA(10, 10),
@@ -35,36 +36,66 @@ func TestImage(t *testing.T) {
}),
}
for _, m := range testImage {
- b := m.(buffered)
- if !Rect(0, 0, 10, 10).Eq(b.Bounds()) {
- t.Errorf("%T: want bounds %v, got %v", b, Rect(0, 0, 10, 10), b.Bounds())
+ if !Rect(0, 0, 10, 10).Eq(m.Bounds()) {
+ t.Errorf("%T: want bounds %v, got %v", m, Rect(0, 0, 10, 10), m.Bounds())
+ continue
+ }
+ if !cmp(t, m.ColorModel(), Transparent, m.At(6, 3)) {
+ t.Errorf("%T: at (6, 3), want a zero color, got %v", m, m.At(6, 3))
continue
}
- if !cmp(t, b.ColorModel(), Transparent, b.At(6, 3)) {
- t.Errorf("%T: at (6, 3), want a zero color, got %v", b, b.At(6, 3))
+ m.Set(6, 3, Opaque)
+ if !cmp(t, m.ColorModel(), Opaque, m.At(6, 3)) {
+ t.Errorf("%T: at (6, 3), want a non-zero color, got %v", m, m.At(6, 3))
continue
}
- b.Set(6, 3, Opaque)
- if !cmp(t, b.ColorModel(), Opaque, b.At(6, 3)) {
- t.Errorf("%T: at (6, 3), want a non-zero color, got %v", b, b.At(6, 3))
+ m = m.SubImage(Rect(3, 2, 9, 8)).(image)
+ if !Rect(3, 2, 9, 8).Eq(m.Bounds()) {
+ t.Errorf("%T: sub-image want bounds %v, got %v", m, Rect(3, 2, 9, 8), m.Bounds())
continue
}
- b = b.SubImage(Rect(3, 2, 9, 8)).(buffered)
- if !Rect(3, 2, 9, 8).Eq(b.Bounds()) {
- t.Errorf("%T: sub-image want bounds %v, got %v", b, Rect(3, 2, 9, 8), b.Bounds())
+ if !cmp(t, m.ColorModel(), Opaque, m.At(6, 3)) {
+ t.Errorf("%T: sub-image at (6, 3), want a non-zero color, got %v", m, m.At(6, 3))
continue
}
- if !cmp(t, b.ColorModel(), Opaque, b.At(6, 3)) {
- t.Errorf("%T: sub-image at (6, 3), want a non-zero color, got %v", b, b.At(6, 3))
+ if !cmp(t, m.ColorModel(), Transparent, m.At(3, 3)) {
+ t.Errorf("%T: sub-image at (3, 3), want a zero color, got %v", m, m.At(3, 3))
continue
}
- if !cmp(t, b.ColorModel(), Transparent, b.At(3, 3)) {
- t.Errorf("%T: sub-image at (3, 3), want a zero color, got %v", b, b.At(3, 3))
+ m.Set(3, 3, Opaque)
+ if !cmp(t, m.ColorModel(), Opaque, m.At(3, 3)) {
+ t.Errorf("%T: sub-image at (3, 3), want a non-zero color, got %v", m, m.At(3, 3))
+ continue
+ }
+ }
+}
+
+func Test16BitsPerColorChannel(t *testing.T) {
+ testColorModel := []ColorModel{
+ RGBA64ColorModel,
+ NRGBA64ColorModel,
+ Alpha16ColorModel,
+ Gray16ColorModel,
+ }
+ for _, cm := range testColorModel {
+ c := cm.Convert(RGBA64Color{0x1234, 0x1234, 0x1234, 0x1234}) // Premultiplied alpha.
+ r, _, _, _ := c.RGBA()
+ if r != 0x1234 {
+ t.Errorf("%T: want red value 0x%04x got 0x%04x", c, 0x1234, r)
continue
}
- b.Set(3, 3, Opaque)
- if !cmp(t, b.ColorModel(), Opaque, b.At(3, 3)) {
- t.Errorf("%T: sub-image at (3, 3), want a non-zero color, got %v", b, b.At(3, 3))
+ }
+ testImage := []image{
+ NewRGBA64(10, 10),
+ NewNRGBA64(10, 10),
+ NewAlpha16(10, 10),
+ NewGray16(10, 10),
+ }
+ for _, m := range testImage {
+ m.Set(1, 2, NRGBA64Color{0xffff, 0xffff, 0xffff, 0x1357}) // Non-premultiplied alpha.
+ r, _, _, _ := m.At(1, 2).RGBA()
+ if r != 0x1357 {
+ t.Errorf("%T: want red value 0x%04x got 0x%04x", m, 0x1357, r)
continue
}
}
diff --git a/src/pkg/io/io.go b/src/pkg/io/io.go
index 846dcacb5..790cf94e7 100644
--- a/src/pkg/io/io.go
+++ b/src/pkg/io/io.go
@@ -12,9 +12,11 @@ import "os"
// Error represents an unexpected I/O behavior.
type Error struct {
- os.ErrorString
+ ErrorString string
}
+func (err *Error) String() string { return err.ErrorString }
+
// ErrShortWrite means that a write accepted fewer bytes than requested
// but failed to return an explicit error.
var ErrShortWrite os.Error = &Error{"short write"}
@@ -29,15 +31,24 @@ var ErrUnexpectedEOF os.Error = &Error{"unexpected EOF"}
// Reader is the interface that wraps the basic Read method.
//
// Read reads up to len(p) bytes into p. It returns the number of bytes
-// read (0 <= n <= len(p)) and any error encountered.
-// Even if Read returns n < len(p),
-// it may use all of p as scratch space during the call.
+// read (0 <= n <= len(p)) and any error encountered. Even if Read
+// returns n < len(p), it may use all of p as scratch space during the call.
// If some data is available but not len(p) bytes, Read conventionally
-// returns what is available rather than block waiting for more.
+// returns what is available instead of waiting for more.
+//
+// When Read encounters an error or end-of-file condition after
+// successfully reading n > 0 bytes, it returns the number of
+// bytes read. It may return the (non-nil) error from the same call
+// or return the error (and n == 0) from a subsequent call.
+// An instance of this general case is that a Reader returning
+// a non-zero number of bytes at the end of the input stream may
+// return either err == os.EOF or err == nil. The next Read should
+// return 0, os.EOF regardless.
//
-// At the end of the input stream, Read returns 0, os.EOF.
-// Read may return a non-zero number of bytes with a non-nil err.
-// In particular, a Read that exhausts the input may return n > 0, os.EOF.
+// Callers should always process the n > 0 bytes returned before
+// considering the error err. Doing so correctly handles I/O errors
+// that happen after reading some bytes and also both of the
+// allowed EOF behaviors.
type Reader interface {
Read(p []byte) (n int, err os.Error)
}
@@ -125,19 +136,22 @@ type WriterTo interface {
// ReaderAt is the interface that wraps the basic ReadAt method.
//
// ReadAt reads len(p) bytes into p starting at offset off in the
-// underlying data stream. It returns the number of bytes
+// underlying input source. It returns the number of bytes
// read (0 <= n <= len(p)) and any error encountered.
//
-// Even if ReadAt returns n < len(p),
-// it may use all of p as scratch space during the call.
-// If some data is available but not len(p) bytes, ReadAt blocks
-// until either all the data is available or an error occurs.
+// When ReadAt returns n < len(p), it returns a non-nil error
+// explaining why more bytes were not returned. In this respect,
+// ReadAt is stricter than Read.
//
-// At the end of the input stream, ReadAt returns 0, os.EOF.
-// ReadAt may return a non-zero number of bytes with a non-nil err.
-// In particular, a ReadAt that exhausts the input may return n > 0, os.EOF.
+// Even if ReadAt returns n < len(p), it may use all of p as scratch
+// space during the call. If some data is available but not len(p) bytes,
+// ReadAt blocks until either all the data is available or an error occurs.
+// In this respect ReadAt is different from Read.
//
-// If ReadAt is reading from an data stream with a seek offset,
+// If the n = len(p) bytes returned by ReadAt are at the end of the
+// input source, ReadAt may return either err == os.EOF or err == nil.
+//
+// If ReadAt is reading from an input source with a seek offset,
// ReadAt should not affect nor be affected by the underlying
// seek offset.
type ReaderAt interface {
@@ -235,7 +249,10 @@ func ReadFull(r Reader, buf []byte) (n int, err os.Error) {
}
// Copyn copies n bytes (or until an error) from src to dst.
-// It returns the number of bytes copied and the error, if any.
+// It returns the number of bytes copied and the earliest
+// error encountered while copying. Because Read can
+// return the full amount requested as well as an error
+// (including os.EOF), so can Copyn.
//
// If dst implements the ReaderFrom interface,
// the copy is implemented by calling dst.ReadFrom(src).
@@ -281,7 +298,11 @@ func Copyn(dst Writer, src Reader, n int64) (written int64, err os.Error) {
// Copy copies from src to dst until either EOF is reached
// on src or an error occurs. It returns the number of bytes
-// copied and the error, if any.
+// copied and the first error encountered while copying, if any.
+//
+// A successful Copy returns err == nil, not err == os.EOF.
+// Because Copy is defined to read from src until EOF, it does
+// not treat an EOF from Read as an error to be reported.
//
// If dst implements the ReaderFrom interface,
// the copy is implemented by calling dst.ReadFrom(src).
diff --git a/src/pkg/io/ioutil/ioutil.go b/src/pkg/io/ioutil/ioutil.go
index 5f1eecaab..f79bf87f5 100644
--- a/src/pkg/io/ioutil/ioutil.go
+++ b/src/pkg/io/ioutil/ioutil.go
@@ -63,7 +63,7 @@ func WriteFile(filename string, data []byte, perm uint32) os.Error {
return err
}
-// A dirList implements sort.Interface.
+// A fileInfoList implements sort.Interface.
type fileInfoList []*os.FileInfo
func (f fileInfoList) Len() int { return len(f) }
diff --git a/src/pkg/mail/message.go b/src/pkg/mail/message.go
index 754b779be..fce287bd8 100644
--- a/src/pkg/mail/message.go
+++ b/src/pkg/mail/message.go
@@ -18,8 +18,10 @@ package mail
import (
"bufio"
"bytes"
+ "encoding/base64"
"fmt"
"io"
+ "io/ioutil"
"log"
"net/textproto"
"os"
@@ -94,7 +96,7 @@ func parseDate(date string) (*time.Time, os.Error) {
return t, nil
}
}
- return nil, os.ErrorString("mail: header could not be parsed")
+ return nil, os.NewError("mail: header could not be parsed")
}
// A Header represents the key-value pairs in a mail message header.
@@ -106,7 +108,7 @@ func (h Header) Get(key string) string {
return textproto.MIMEHeader(h).Get(key)
}
-var ErrHeaderNotPresent = os.ErrorString("mail: header not in message")
+var ErrHeaderNotPresent = os.NewError("mail: header not in message")
// Date parses the Date header field.
func (h Header) Date() (*time.Time, os.Error) {
@@ -202,7 +204,7 @@ func (p *addrParser) parseAddressList() ([]*Address, os.Error) {
break
}
if !p.consume(',') {
- return nil, os.ErrorString("mail: expected comma")
+ return nil, os.NewError("mail: expected comma")
}
}
return list, nil
@@ -213,7 +215,7 @@ func (p *addrParser) parseAddress() (addr *Address, err os.Error) {
debug.Printf("parseAddress: %q", *p)
p.skipSpace()
if p.empty() {
- return nil, os.ErrorString("mail: no address")
+ return nil, os.NewError("mail: no address")
}
// address = name-addr / addr-spec
@@ -244,14 +246,14 @@ func (p *addrParser) parseAddress() (addr *Address, err os.Error) {
// angle-addr = "<" addr-spec ">"
p.skipSpace()
if !p.consume('<') {
- return nil, os.ErrorString("mail: no angle-addr")
+ return nil, os.NewError("mail: no angle-addr")
}
spec, err = p.consumeAddrSpec()
if err != nil {
return nil, err
}
if !p.consume('>') {
- return nil, os.ErrorString("mail: unclosed angle-addr")
+ return nil, os.NewError("mail: unclosed angle-addr")
}
debug.Printf("parseAddress: spec=%q", spec)
@@ -276,7 +278,7 @@ func (p *addrParser) consumeAddrSpec() (spec string, err os.Error) {
var localPart string
p.skipSpace()
if p.empty() {
- return "", os.ErrorString("mail: no addr-spec")
+ return "", os.NewError("mail: no addr-spec")
}
if p.peek() == '"' {
// quoted-string
@@ -293,14 +295,14 @@ func (p *addrParser) consumeAddrSpec() (spec string, err os.Error) {
}
if !p.consume('@') {
- return "", os.ErrorString("mail: missing @ in addr-spec")
+ return "", os.NewError("mail: missing @ in addr-spec")
}
// domain = dot-atom / domain-literal
var domain string
p.skipSpace()
if p.empty() {
- return "", os.ErrorString("mail: no domain in addr-spec")
+ return "", os.NewError("mail: no domain in addr-spec")
}
// TODO(dsymonds): Handle domain-literal
domain, err = p.consumeAtom(true)
@@ -321,7 +323,7 @@ func (p *addrParser) consumePhrase() (phrase string, err os.Error) {
var word string
p.skipSpace()
if p.empty() {
- return "", os.ErrorString("mail: missing phrase")
+ return "", os.NewError("mail: missing phrase")
}
if p.peek() == '"' {
// quoted-string
@@ -345,7 +347,7 @@ func (p *addrParser) consumePhrase() (phrase string, err os.Error) {
// Ignore any error if we got at least one word.
if err != nil && len(words) == 0 {
debug.Printf("consumePhrase: hit err: %v", err)
- return "", os.ErrorString("mail: missing word in phrase")
+ return "", os.NewError("mail: missing word in phrase")
}
phrase = strings.Join(words, " ")
return phrase, nil
@@ -359,14 +361,14 @@ func (p *addrParser) consumeQuotedString() (qs string, err os.Error) {
Loop:
for {
if i >= p.len() {
- return "", os.ErrorString("mail: unclosed quoted-string")
+ return "", os.NewError("mail: unclosed quoted-string")
}
switch c := (*p)[i]; {
case c == '"':
break Loop
case c == '\\':
if i+1 == p.len() {
- return "", os.ErrorString("mail: unclosed quoted-string")
+ return "", os.NewError("mail: unclosed quoted-string")
}
qsb = append(qsb, (*p)[i+1])
i += 2
@@ -387,7 +389,7 @@ Loop:
// If dot is true, consumeAtom parses an RFC 5322 dot-atom instead.
func (p *addrParser) consumeAtom(dot bool) (atom string, err os.Error) {
if !isAtext(p.peek(), false) {
- return "", os.ErrorString("mail: invalid string")
+ return "", os.NewError("mail: invalid string")
}
i := 1
for ; i < p.len() && isAtext((*p)[i], dot); i++ {
@@ -425,40 +427,71 @@ func (p *addrParser) len() int {
func decodeRFC2047Word(s string) (string, os.Error) {
fields := strings.Split(s, "?", -1)
if len(fields) != 5 || fields[0] != "=" || fields[4] != "=" {
- return "", os.ErrorString("mail: address not RFC 2047 encoded")
+ return "", os.NewError("mail: address not RFC 2047 encoded")
}
charset, enc := strings.ToLower(fields[1]), strings.ToLower(fields[2])
- // TODO(dsymonds): Support "b" encoding too.
- if enc != "q" {
- return "", fmt.Errorf("mail: RFC 2047 encoding not supported: %q", enc)
- }
if charset != "iso-8859-1" && charset != "utf-8" {
return "", fmt.Errorf("mail: charset not supported: %q", charset)
}
- in := fields[3]
- b := new(bytes.Buffer)
- for i := 0; i < len(in); i++ {
- switch c := in[i]; {
- case c == '=' && i+2 < len(in):
- x, err := strconv.Btoi64(in[i+1:i+3], 16)
- if err != nil {
- return "", fmt.Errorf("mail: invalid RFC 2047 encoding: %q", in[i:i+3])
- }
- i += 2
- switch charset {
- case "iso-8859-1":
- b.WriteRune(int(x))
- case "utf-8":
- b.WriteByte(byte(x))
- }
- case c == '_':
- b.WriteByte(' ')
- default:
- b.WriteByte(c)
+ in := bytes.NewBufferString(fields[3])
+ var r io.Reader
+ switch enc {
+ case "b":
+ r = base64.NewDecoder(base64.StdEncoding, in)
+ case "q":
+ r = qDecoder{r: in}
+ default:
+ return "", fmt.Errorf("mail: RFC 2047 encoding not supported: %q", enc)
+ }
+
+ dec, err := ioutil.ReadAll(r)
+ if err != nil {
+ return "", err
+ }
+
+ switch charset {
+ case "iso-8859-1":
+ b := new(bytes.Buffer)
+ for _, c := range dec {
+ b.WriteRune(int(c))
+ }
+ return b.String(), nil
+ case "utf-8":
+ return string(dec), nil
+ }
+ panic("unreachable")
+}
+
+type qDecoder struct {
+ r io.Reader
+ scratch [2]byte
+}
+
+func (qd qDecoder) Read(p []byte) (n int, err os.Error) {
+ // This method writes at most one byte into p.
+ if len(p) == 0 {
+ return 0, nil
+ }
+ if _, err := qd.r.Read(qd.scratch[:1]); err != nil {
+ return 0, err
+ }
+ switch c := qd.scratch[0]; {
+ case c == '=':
+ if _, err := io.ReadFull(qd.r, qd.scratch[:2]); err != nil {
+ return 0, err
+ }
+ x, err := strconv.Btoi64(string(qd.scratch[:2]), 16)
+ if err != nil {
+ return 0, fmt.Errorf("mail: invalid RFC 2047 encoding: %q", qd.scratch[:2])
}
+ p[0] = byte(x)
+ case c == '_':
+ p[0] = ' '
+ default:
+ p[0] = c
}
- return b.String(), nil
+ return 1, nil
}
var atextChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
diff --git a/src/pkg/mail/message_test.go b/src/pkg/mail/message_test.go
index 1ff45d2c1..e1bcc89ee 100644
--- a/src/pkg/mail/message_test.go
+++ b/src/pkg/mail/message_test.go
@@ -217,6 +217,26 @@ func TestAddressParsing(t *testing.T) {
},
},
},
+ // Custom example of RFC 2047 "B"-encoded ISO-8859-1 address.
+ {
+ `=?ISO-8859-1?B?SvZyZw==?= <joerg@example.com>`,
+ []*Address{
+ &Address{
+ Name: `Jörg`,
+ Address: "joerg@example.com",
+ },
+ },
+ },
+ // Custom example of RFC 2047 "B"-encoded UTF-8 address.
+ {
+ `=?UTF-8?B?SsO2cmc=?= <joerg@example.com>`,
+ []*Address{
+ &Address{
+ Name: `Jörg`,
+ Address: "joerg@example.com",
+ },
+ },
+ },
}
for _, test := range tests {
addrs, err := newAddrParser(test.addrsStr).parseAddressList()
diff --git a/src/pkg/mime/grammar.go b/src/pkg/mime/grammar.go
index e60cbb8df..6e319ff8b 100644
--- a/src/pkg/mime/grammar.go
+++ b/src/pkg/mime/grammar.go
@@ -9,13 +9,13 @@ import (
)
// isTSpecial returns true if rune is in 'tspecials' as defined by RFC
-// 1531 and RFC 2045.
+// 1521 and RFC 2045.
func isTSpecial(rune int) bool {
return strings.IndexRune(`()<>@,;:\"/[]?=`, rune) != -1
}
// IsTokenChar returns true if rune is in 'token' as defined by RFC
-// 1531 and RFC 2045.
+// 1521 and RFC 2045.
func IsTokenChar(rune int) bool {
// token := 1*<any (US-ASCII) CHAR except SPACE, CTLs,
// or tspecials>
diff --git a/src/pkg/mime/mediatype.go b/src/pkg/mime/mediatype.go
index f28ff3e96..a270cb937 100644
--- a/src/pkg/mime/mediatype.go
+++ b/src/pkg/mime/mediatype.go
@@ -31,7 +31,7 @@ func validMediaTypeOrDisposition(s string) bool {
}
// ParseMediaType parses a media type value and any optional
-// parameters, per RFC 1531. Media types are the values in
+// parameters, per RFC 1521. Media types are the values in
// Content-Type and Content-Disposition headers (RFC 2183). On
// success, ParseMediaType returns the media type converted to
// lowercase and trimmed of white space and a non-nil params. On
diff --git a/src/pkg/mime/multipart/formdata.go b/src/pkg/mime/multipart/formdata.go
index 5f3286565..91404d6f4 100644
--- a/src/pkg/mime/multipart/formdata.go
+++ b/src/pkg/mime/multipart/formdata.go
@@ -19,7 +19,7 @@ import (
// a Content-Disposition of "form-data".
// It stores up to maxMemory bytes of the file parts in memory
// and the remainder on disk in temporary files.
-func (r *multiReader) ReadForm(maxMemory int64) (f *Form, err os.Error) {
+func (r *Reader) ReadForm(maxMemory int64) (f *Form, err os.Error) {
form := &Form{make(map[string][]string), make(map[string][]*FileHeader)}
defer func() {
if err != nil {
diff --git a/src/pkg/mime/multipart/formdata_test.go b/src/pkg/mime/multipart/formdata_test.go
index 9424c3778..4bc464931 100644
--- a/src/pkg/mime/multipart/formdata_test.go
+++ b/src/pkg/mime/multipart/formdata_test.go
@@ -31,10 +31,12 @@ func TestReadForm(t *testing.T) {
if _, ok := fd.(*os.File); ok {
t.Error("file is *os.File, should not be")
}
+ fd.Close()
fd = testFile(t, f.File["fileb"][0], "fileb.txt", filebContents)
if _, ok := fd.(*os.File); !ok {
t.Errorf("file has unexpected underlying type %T", fd)
}
+ fd.Close()
}
func testFile(t *testing.T, fh *FileHeader, efn, econtent string) File {
diff --git a/src/pkg/mime/multipart/multipart.go b/src/pkg/mime/multipart/multipart.go
index 9affa1126..5c173f228 100644
--- a/src/pkg/mime/multipart/multipart.go
+++ b/src/pkg/mime/multipart/multipart.go
@@ -28,21 +28,6 @@ var headerRegexp *regexp.Regexp = regexp.MustCompile("^([a-zA-Z0-9\\-]+): *([^\r
var emptyParams = make(map[string]string)
-// Reader is an iterator over parts in a MIME multipart body.
-// Reader's underlying parser consumes its input as needed. Seeking
-// isn't supported.
-type Reader interface {
- // NextPart returns the next part in the multipart or an error.
- // When there are no more parts, the error os.EOF is returned.
- NextPart() (*Part, os.Error)
-
- // ReadForm parses an entire multipart message whose parts have
- // a Content-Disposition of "form-data".
- // It stores up to maxMemory bytes of the file parts in memory
- // and the remainder on disk in temporary files.
- ReadForm(maxMemory int64) (*Form, os.Error)
-}
-
// A Part represents a single part in a multipart body.
type Part struct {
// The headers of the body, if any, with the keys canonicalized
@@ -51,7 +36,7 @@ type Part struct {
Header textproto.MIMEHeader
buffer *bytes.Buffer
- mr *multiReader
+ mr *Reader
disposition string
dispositionParams map[string]string
@@ -91,9 +76,9 @@ func (p *Part) parseContentDisposition() {
// NewReader creates a new multipart Reader reading from r using the
// given MIME boundary.
-func NewReader(reader io.Reader, boundary string) Reader {
+func NewReader(reader io.Reader, boundary string) *Reader {
b := []byte("\r\n--" + boundary + "--")
- return &multiReader{
+ return &Reader{
bufReader: bufio.NewReader(reader),
nlDashBoundary: b[:len(b)-2],
@@ -102,9 +87,7 @@ func NewReader(reader io.Reader, boundary string) Reader {
}
}
-// Implementation ....
-
-func newPart(mr *multiReader) (*Part, os.Error) {
+func newPart(mr *Reader) (*Part, os.Error) {
bp := &Part{
Header: make(map[string][]string),
mr: mr,
@@ -188,7 +171,10 @@ func (bp *Part) Close() os.Error {
return nil
}
-type multiReader struct {
+// Reader is an iterator over parts in a MIME multipart body.
+// Reader's underlying parser consumes its input as needed. Seeking
+// isn't supported.
+type Reader struct {
bufReader *bufio.Reader
currentPart *Part
@@ -197,7 +183,9 @@ type multiReader struct {
nlDashBoundary, dashBoundaryDash, dashBoundary []byte
}
-func (mr *multiReader) NextPart() (*Part, os.Error) {
+// NextPart returns the next part in the multipart or an error.
+// When there are no more parts, the error os.EOF is returned.
+func (mr *Reader) NextPart() (*Part, os.Error) {
if mr.currentPart != nil {
mr.currentPart.Close()
}
@@ -247,7 +235,7 @@ func (mr *multiReader) NextPart() (*Part, os.Error) {
panic("unreachable")
}
-func (mr *multiReader) isBoundaryDelimiterLine(line []byte) bool {
+func (mr *Reader) isBoundaryDelimiterLine(line []byte) bool {
// http://tools.ietf.org/html/rfc2046#section-5.1
// The boundary delimiter line is then defined as a line
// consisting entirely of two hyphen characters ("-",
diff --git a/src/pkg/mime/multipart/multipart_test.go b/src/pkg/mime/multipart/multipart_test.go
index 4ec3d30bd..8bc16bbf7 100644
--- a/src/pkg/mime/multipart/multipart_test.go
+++ b/src/pkg/mime/multipart/multipart_test.go
@@ -25,7 +25,7 @@ func TestHorizontalWhitespace(t *testing.T) {
}
func TestBoundaryLine(t *testing.T) {
- mr := NewReader(strings.NewReader(""), "myBoundary").(*multiReader)
+ mr := NewReader(strings.NewReader(""), "myBoundary")
if !mr.isBoundaryDelimiterLine([]byte("--myBoundary\r\n")) {
t.Error("expected")
}
diff --git a/src/pkg/mime/multipart/writer.go b/src/pkg/mime/multipart/writer.go
index b436dd012..97a8897b2 100644
--- a/src/pkg/mime/multipart/writer.go
+++ b/src/pkg/mime/multipart/writer.go
@@ -61,7 +61,11 @@ func (w *Writer) CreatePart(header textproto.MIMEHeader) (io.Writer, os.Error) {
}
}
var b bytes.Buffer
- fmt.Fprintf(&b, "\r\n--%s\r\n", w.boundary)
+ if w.lastpart != nil {
+ fmt.Fprintf(&b, "\r\n--%s\r\n", w.boundary)
+ } else {
+ fmt.Fprintf(&b, "--%s\r\n", w.boundary)
+ }
// TODO(bradfitz): move this to textproto.MimeHeader.Write(w), have it sort
// and clean, like http.Header.Write(w) does.
for k, vv := range header {
diff --git a/src/pkg/mime/multipart/writer_test.go b/src/pkg/mime/multipart/writer_test.go
index e6a04c388..494e936c4 100644
--- a/src/pkg/mime/multipart/writer_test.go
+++ b/src/pkg/mime/multipart/writer_test.go
@@ -30,6 +30,13 @@ func TestWriter(t *testing.T) {
if err != nil {
t.Fatalf("Close: %v", err)
}
+ s := b.String()
+ if len(s) == 0 {
+ t.Fatal("String: unexpected empty result")
+ }
+ if s[0] == '\r' || s[0] == '\n' {
+ t.Fatal("String: unexpected newline")
+ }
}
r := NewReader(&b, w.Boundary())
diff --git a/src/pkg/net/Makefile b/src/pkg/net/Makefile
index 5472df392..536fe369d 100644
--- a/src/pkg/net/Makefile
+++ b/src/pkg/net/Makefile
@@ -7,6 +7,7 @@ include ../../Make.inc
TARG=net
GOFILES=\
dial.go\
+ dnsclient.go\
dnsmsg.go\
fd_$(GOOS).go\
hosts.go\
@@ -14,7 +15,6 @@ GOFILES=\
ip.go\
ipsock.go\
iprawsock.go\
- lookup.go\
net.go\
parse.go\
pipe.go\
@@ -24,11 +24,12 @@ GOFILES=\
unixsock.go\
GOFILES_freebsd=\
- dnsclient.go\
+ dnsclient_unix.go\
dnsconfig.go\
fd.go\
file.go\
interface_bsd.go\
+ lookup_unix.go\
newpollserver.go\
port.go\
sendfile_stub.go\
@@ -39,11 +40,12 @@ CGOFILES_freebsd=\
cgo_unix.go\
GOFILES_darwin=\
- dnsclient.go\
+ dnsclient_unix.go\
dnsconfig.go\
fd.go\
file.go\
interface_bsd.go\
+ lookup_unix.go\
newpollserver.go\
port.go\
sendfile_stub.go\
@@ -54,11 +56,12 @@ CGOFILES_darwin=\
cgo_unix.go\
GOFILES_linux=\
- dnsclient.go\
+ dnsclient_unix.go\
dnsconfig.go\
fd.go\
file.go\
interface_linux.go\
+ lookup_unix.go\
newpollserver.go\
port.go\
sendfile_linux.go\
@@ -66,6 +69,7 @@ GOFILES_linux=\
GOFILES_plan9=\
interface_stub.go\
+ lookup_unix.go\
sendfile_stub.go\
ifeq ($(GOARCH),arm)
@@ -78,11 +82,10 @@ CGOFILES_linux=\
endif
GOFILES_windows=\
- cgo_stub.go\
file_windows.go\
- interface_stub.go\
- resolv_windows.go\
- sendfile_stub.go\
+ interface_windows.go\
+ lookup_windows.go\
+ sendfile_windows.go\
sock_windows.go\
GOFILES+=$(GOFILES_$(GOOS))
diff --git a/src/pkg/net/dnsclient.go b/src/pkg/net/dnsclient.go
index ae9ca8430..280b19453 100644
--- a/src/pkg/net/dnsclient.go
+++ b/src/pkg/net/dnsclient.go
@@ -2,16 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// DNS client: see RFC 1035.
-// Has to be linked into package net for Dial.
-
-// TODO(rsc):
-// Check periodically whether /etc/resolv.conf has changed.
-// Could potentially handle many outstanding lookups faster.
-// Could have a small cache.
-// Random UDP source port (net.Dial should do that for us).
-// Random request IDs.
-
package net
import (
@@ -19,9 +9,6 @@ import (
"fmt"
"os"
"rand"
- "sync"
- "time"
- "sort"
)
// DNSError represents a DNS lookup error.
@@ -49,54 +36,31 @@ func (e *DNSError) Temporary() bool { return e.IsTimeout }
const noSuchHost = "no such host"
-// Send a request on the connection and hope for a reply.
-// Up to cfg.attempts attempts.
-func exchange(cfg *dnsConfig, c Conn, name string, qtype uint16) (*dnsMsg, os.Error) {
- if len(name) >= 256 {
- return nil, &DNSError{Error: "name too long", Name: name}
- }
- out := new(dnsMsg)
- out.id = uint16(rand.Int()) ^ uint16(time.Nanoseconds())
- out.question = []dnsQuestion{
- {name, qtype, dnsClassINET},
- }
- out.recursion_desired = true
- msg, ok := out.Pack()
- if !ok {
- return nil, &DNSError{Error: "internal error - cannot pack message", Name: name}
+// reverseaddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP
+// address addr suitable for rDNS (PTR) record lookup or an error if it fails
+// to parse the IP address.
+func reverseaddr(addr string) (arpa string, err os.Error) {
+ ip := ParseIP(addr)
+ if ip == nil {
+ return "", &DNSError{Error: "unrecognized address", Name: addr}
}
-
- for attempt := 0; attempt < cfg.attempts; attempt++ {
- n, err := c.Write(msg)
- if err != nil {
- return nil, err
- }
-
- c.SetReadTimeout(int64(cfg.timeout) * 1e9) // nanoseconds
-
- buf := make([]byte, 2000) // More than enough.
- n, err = c.Read(buf)
- if err != nil {
- if e, ok := err.(Error); ok && e.Timeout() {
- continue
- }
- return nil, err
- }
- buf = buf[0:n]
- in := new(dnsMsg)
- if !in.Unpack(buf) || in.id != out.id {
- continue
- }
- return in, nil
+ if ip.To4() != nil {
+ return fmt.Sprintf("%d.%d.%d.%d.in-addr.arpa.", ip[15], ip[14], ip[13], ip[12]), nil
}
- var server string
- if a := c.RemoteAddr(); a != nil {
- server = a.String()
+ // Must be IPv6
+ var buf bytes.Buffer
+ // Add it, in reverse, to the buffer
+ for i := len(ip) - 1; i >= 0; i-- {
+ s := fmt.Sprintf("%02x", ip[i])
+ buf.WriteByte(s[1])
+ buf.WriteByte('.')
+ buf.WriteByte(s[0])
+ buf.WriteByte('.')
}
- return nil, &DNSError{Error: "no answer from server", Name: name, Server: server, IsTimeout: true}
+ // Append "ip6.arpa." and return (buf already has the final .)
+ return buf.String() + "ip6.arpa.", nil
}
-
// Find answer for name in dns message.
// On return, if err == nil, addrs != nil.
func answer(name, server string, dns *dnsMsg, qtype uint16) (cname string, addrs []dnsRR, err os.Error) {
@@ -150,63 +114,6 @@ Cname:
return "", nil, &DNSError{Error: "too many redirects", Name: name, Server: server}
}
-// Do a lookup for a single name, which must be rooted
-// (otherwise answer will not find the answers).
-func tryOneName(cfg *dnsConfig, name string, qtype uint16) (cname string, addrs []dnsRR, err os.Error) {
- if len(cfg.servers) == 0 {
- return "", nil, &DNSError{Error: "no DNS servers", Name: name}
- }
- for i := 0; i < len(cfg.servers); i++ {
- // Calling Dial here is scary -- we have to be sure
- // not to dial a name that will require a DNS lookup,
- // or Dial will call back here to translate it.
- // The DNS config parser has already checked that
- // all the cfg.servers[i] are IP addresses, which
- // Dial will use without a DNS lookup.
- server := cfg.servers[i] + ":53"
- c, cerr := Dial("udp", server)
- if cerr != nil {
- err = cerr
- continue
- }
- msg, merr := exchange(cfg, c, name, qtype)
- c.Close()
- if merr != nil {
- err = merr
- continue
- }
- cname, addrs, err = answer(name, server, msg, qtype)
- if err == nil || err.(*DNSError).Error == noSuchHost {
- break
- }
- }
- return
-}
-
-func convertRR_A(records []dnsRR) []IP {
- addrs := make([]IP, len(records))
- for i, rr := range records {
- a := rr.(*dnsRR_A).A
- addrs[i] = IPv4(byte(a>>24), byte(a>>16), byte(a>>8), byte(a))
- }
- return addrs
-}
-
-func convertRR_AAAA(records []dnsRR) []IP {
- addrs := make([]IP, len(records))
- for i, rr := range records {
- a := make(IP, 16)
- copy(a, rr.(*dnsRR_AAAA).AAAA[:])
- addrs[i] = a
- }
- return addrs
-}
-
-var cfg *dnsConfig
-var dnserr os.Error
-
-func loadConfig() { cfg, dnserr = dnsReadConfig() }
-
func isDomainName(s string) bool {
// See RFC 1035, RFC 3696.
if len(s) == 0 {
@@ -255,141 +162,6 @@ func isDomainName(s string) bool {
return ok
}
-var onceLoadConfig sync.Once
-
-func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err os.Error) {
- if !isDomainName(name) {
- return name, nil, &DNSError{Error: "invalid domain name", Name: name}
- }
- onceLoadConfig.Do(loadConfig)
- if dnserr != nil || cfg == nil {
- err = dnserr
- return
- }
- // If name is rooted (trailing dot) or has enough dots,
- // try it by itself first.
- rooted := len(name) > 0 && name[len(name)-1] == '.'
- if rooted || count(name, '.') >= cfg.ndots {
- rname := name
- if !rooted {
- rname += "."
- }
- // Can try as ordinary name.
- cname, addrs, err = tryOneName(cfg, rname, qtype)
- if err == nil {
- return
- }
- }
- if rooted {
- return
- }
-
- // Otherwise, try suffixes.
- for i := 0; i < len(cfg.search); i++ {
- rname := name + "." + cfg.search[i]
- if rname[len(rname)-1] != '.' {
- rname += "."
- }
- cname, addrs, err = tryOneName(cfg, rname, qtype)
- if err == nil {
- return
- }
- }
-
- // Last ditch effort: try unsuffixed.
- rname := name
- if !rooted {
- rname += "."
- }
- cname, addrs, err = tryOneName(cfg, rname, qtype)
- if err == nil {
- return
- }
- return
-}
-
-// goLookupHost is the native Go implementation of LookupHost.
-// Used only if cgoLookupHost refuses to handle the request
-// (that is, only if cgoLookupHost is the stub in cgo_stub.go).
-// Normally we let cgo use the C library resolver instead of
-// depending on our lookup code, so that Go and C get the same
-// answers.
-func goLookupHost(name string) (addrs []string, err os.Error) {
- // Use entries from /etc/hosts if they match.
- addrs = lookupStaticHost(name)
- if len(addrs) > 0 {
- return
- }
- onceLoadConfig.Do(loadConfig)
- if dnserr != nil || cfg == nil {
- err = dnserr
- return
- }
- ips, err := goLookupIP(name)
- if err != nil {
- return
- }
- addrs = make([]string, 0, len(ips))
- for _, ip := range ips {
- addrs = append(addrs, ip.String())
- }
- return
-}
-
-// goLookupIP is the native Go implementation of LookupIP.
-// Used only if cgoLookupIP refuses to handle the request
-// (that is, only if cgoLookupIP is the stub in cgo_stub.go).
-// Normally we let cgo use the C library resolver instead of
-// depending on our lookup code, so that Go and C get the same
-// answers.
-func goLookupIP(name string) (addrs []IP, err os.Error) {
- onceLoadConfig.Do(loadConfig)
- if dnserr != nil || cfg == nil {
- err = dnserr
- return
- }
- var records []dnsRR
- var cname string
- cname, records, err = lookup(name, dnsTypeA)
- if err != nil {
- return
- }
- addrs = convertRR_A(records)
- if cname != "" {
- name = cname
- }
- _, records, err = lookup(name, dnsTypeAAAA)
- if err != nil && len(addrs) > 0 {
- // Ignore error because A lookup succeeded.
- err = nil
- }
- if err != nil {
- return
- }
- addrs = append(addrs, convertRR_AAAA(records)...)
- return
-}
-
-// goLookupCNAME is the native Go implementation of LookupCNAME.
-// Used only if cgoLookupCNAME refuses to handle the request
-// (that is, only if cgoLookupCNAME is the stub in cgo_stub.go).
-// Normally we let cgo use the C library resolver instead of
-// depending on our lookup code, so that Go and C get the same
-// answers.
-func goLookupCNAME(name string) (cname string, err os.Error) {
- onceLoadConfig.Do(loadConfig)
- if dnserr != nil || cfg == nil {
- err = dnserr
- return
- }
- _, rr, err := lookup(name, dnsTypeCNAME)
- if err != nil {
- return
- }
- cname = rr[0].(*dnsRR_CNAME).Cname
- return
-}
-
// An SRV represents a single DNS SRV record.
type SRV struct {
Target string
@@ -436,35 +208,6 @@ func shuffleSRVByWeight(addrs []*SRV) {
}
}
-// LookupSRV tries to resolve an SRV query of the given service,
-// protocol, and domain name, as specified in RFC 2782. In most cases
-// the proto argument can be the same as the corresponding
-// Addr.Network(). The returned records are sorted by priority
-// and randomized by weight within a priority.
-func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os.Error) {
- target := "_" + service + "._" + proto + "." + name
- var records []dnsRR
- cname, records, err = lookup(target, dnsTypeSRV)
- if err != nil {
- return
- }
- addrs = make([]*SRV, len(records))
- for i, rr := range records {
- r := rr.(*dnsRR_SRV)
- addrs[i] = &SRV{r.Target, r.Port, r.Priority, r.Weight}
- }
- sort.Sort(byPriorityWeight(addrs))
- i := 0
- for j := 1; j < len(addrs); j++ {
- if addrs[i].Priority != addrs[j].Priority {
- shuffleSRVByWeight(addrs[i:j])
- i = j
- }
- }
- shuffleSRVByWeight(addrs[i:len(addrs)])
- return
-}
-
// An MX represents a single DNS MX record.
type MX struct {
Host string
@@ -479,73 +222,3 @@ func (s byPref) Len() int { return len(s) }
func (s byPref) Less(i, j int) bool { return s[i].Pref < s[j].Pref }
func (s byPref) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
-
-// LookupMX returns the DNS MX records for the given domain name sorted by preference.
-func LookupMX(name string) (mx []*MX, err os.Error) {
- _, rr, err := lookup(name, dnsTypeMX)
- if err != nil {
- return
- }
- mx = make([]*MX, len(rr))
- for i := range rr {
- r := rr[i].(*dnsRR_MX)
- mx[i] = &MX{r.Mx, r.Pref}
- }
- // Shuffle the records to match RFC 5321 when sorted
- for i := range mx {
- j := rand.Intn(i + 1)
- mx[i], mx[j] = mx[j], mx[i]
- }
- sort.Sort(byPref(mx))
- return
-}
-
-// reverseaddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP
-// address addr suitable for rDNS (PTR) record lookup or an error if it fails
-// to parse the IP address.
-func reverseaddr(addr string) (arpa string, err os.Error) {
- ip := ParseIP(addr)
- if ip == nil {
- return "", &DNSError{Error: "unrecognized address", Name: addr}
- }
- if ip.To4() != nil {
- return fmt.Sprintf("%d.%d.%d.%d.in-addr.arpa.", ip[15], ip[14], ip[13], ip[12]), nil
- }
- // Must be IPv6
- var buf bytes.Buffer
- // Add it, in reverse, to the buffer
- for i := len(ip) - 1; i >= 0; i-- {
- s := fmt.Sprintf("%02x", ip[i])
- buf.WriteByte(s[1])
- buf.WriteByte('.')
- buf.WriteByte(s[0])
- buf.WriteByte('.')
- }
- // Append "ip6.arpa." and return (buf already has the final .)
- return buf.String() + "ip6.arpa.", nil
-}
-
-// LookupAddr performs a reverse lookup for the given address, returning a list
-// of names mapping to that address.
-func LookupAddr(addr string) (name []string, err os.Error) {
- name = lookupStaticAddr(addr)
- if len(name) > 0 {
- return
- }
- var arpa string
- arpa, err = reverseaddr(addr)
- if err != nil {
- return
- }
- var records []dnsRR
- _, records, err = lookup(arpa, dnsTypePTR)
- if err != nil {
- return
- }
- name = make([]string, len(records))
- for i := range records {
- r := records[i].(*dnsRR_PTR)
- name[i] = r.Ptr
- }
- return
-}
diff --git a/src/pkg/net/dnsclient_unix.go b/src/pkg/net/dnsclient_unix.go
new file mode 100644
index 000000000..7f3ef2878
--- /dev/null
+++ b/src/pkg/net/dnsclient_unix.go
@@ -0,0 +1,262 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// DNS client: see RFC 1035.
+// Has to be linked into package net for Dial.
+
+// TODO(rsc):
+// Check periodically whether /etc/resolv.conf has changed.
+// Could potentially handle many outstanding lookups faster.
+// Could have a small cache.
+// Random UDP source port (net.Dial should do that for us).
+// Random request IDs.
+
+package net
+
+import (
+ "os"
+ "rand"
+ "sync"
+ "time"
+)
+
+// Send a request on the connection and hope for a reply.
+// Up to cfg.attempts attempts.
+func exchange(cfg *dnsConfig, c Conn, name string, qtype uint16) (*dnsMsg, os.Error) {
+ if len(name) >= 256 {
+ return nil, &DNSError{Error: "name too long", Name: name}
+ }
+ out := new(dnsMsg)
+ out.id = uint16(rand.Int()) ^ uint16(time.Nanoseconds())
+ out.question = []dnsQuestion{
+ {name, qtype, dnsClassINET},
+ }
+ out.recursion_desired = true
+ msg, ok := out.Pack()
+ if !ok {
+ return nil, &DNSError{Error: "internal error - cannot pack message", Name: name}
+ }
+
+ for attempt := 0; attempt < cfg.attempts; attempt++ {
+ n, err := c.Write(msg)
+ if err != nil {
+ return nil, err
+ }
+
+ c.SetReadTimeout(int64(cfg.timeout) * 1e9) // nanoseconds
+
+ buf := make([]byte, 2000) // More than enough.
+ n, err = c.Read(buf)
+ if err != nil {
+ if e, ok := err.(Error); ok && e.Timeout() {
+ continue
+ }
+ return nil, err
+ }
+ buf = buf[0:n]
+ in := new(dnsMsg)
+ if !in.Unpack(buf) || in.id != out.id {
+ continue
+ }
+ return in, nil
+ }
+ var server string
+ if a := c.RemoteAddr(); a != nil {
+ server = a.String()
+ }
+ return nil, &DNSError{Error: "no answer from server", Name: name, Server: server, IsTimeout: true}
+}
+
+
+// Do a lookup for a single name, which must be rooted
+// (otherwise answer will not find the answers).
+func tryOneName(cfg *dnsConfig, name string, qtype uint16) (cname string, addrs []dnsRR, err os.Error) {
+ if len(cfg.servers) == 0 {
+ return "", nil, &DNSError{Error: "no DNS servers", Name: name}
+ }
+ for i := 0; i < len(cfg.servers); i++ {
+ // Calling Dial here is scary -- we have to be sure
+ // not to dial a name that will require a DNS lookup,
+ // or Dial will call back here to translate it.
+ // The DNS config parser has already checked that
+ // all the cfg.servers[i] are IP addresses, which
+ // Dial will use without a DNS lookup.
+ server := cfg.servers[i] + ":53"
+ c, cerr := Dial("udp", server)
+ if cerr != nil {
+ err = cerr
+ continue
+ }
+ msg, merr := exchange(cfg, c, name, qtype)
+ c.Close()
+ if merr != nil {
+ err = merr
+ continue
+ }
+ cname, addrs, err = answer(name, server, msg, qtype)
+ if err == nil || err.(*DNSError).Error == noSuchHost {
+ break
+ }
+ }
+ return
+}
+
+func convertRR_A(records []dnsRR) []IP {
+ addrs := make([]IP, len(records))
+ for i, rr := range records {
+ a := rr.(*dnsRR_A).A
+ addrs[i] = IPv4(byte(a>>24), byte(a>>16), byte(a>>8), byte(a))
+ }
+ return addrs
+}
+
+func convertRR_AAAA(records []dnsRR) []IP {
+ addrs := make([]IP, len(records))
+ for i, rr := range records {
+ a := make(IP, 16)
+ copy(a, rr.(*dnsRR_AAAA).AAAA[:])
+ addrs[i] = a
+ }
+ return addrs
+}
+
+var cfg *dnsConfig
+var dnserr os.Error
+
+func loadConfig() { cfg, dnserr = dnsReadConfig() }
+
+var onceLoadConfig sync.Once
+
+func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err os.Error) {
+ if !isDomainName(name) {
+ return name, nil, &DNSError{Error: "invalid domain name", Name: name}
+ }
+ onceLoadConfig.Do(loadConfig)
+ if dnserr != nil || cfg == nil {
+ err = dnserr
+ return
+ }
+ // If name is rooted (trailing dot) or has enough dots,
+ // try it by itself first.
+ rooted := len(name) > 0 && name[len(name)-1] == '.'
+ if rooted || count(name, '.') >= cfg.ndots {
+ rname := name
+ if !rooted {
+ rname += "."
+ }
+ // Can try as ordinary name.
+ cname, addrs, err = tryOneName(cfg, rname, qtype)
+ if err == nil {
+ return
+ }
+ }
+ if rooted {
+ return
+ }
+
+ // Otherwise, try suffixes.
+ for i := 0; i < len(cfg.search); i++ {
+ rname := name + "." + cfg.search[i]
+ if rname[len(rname)-1] != '.' {
+ rname += "."
+ }
+ cname, addrs, err = tryOneName(cfg, rname, qtype)
+ if err == nil {
+ return
+ }
+ }
+
+ // Last ditch effort: try unsuffixed.
+ rname := name
+ if !rooted {
+ rname += "."
+ }
+ cname, addrs, err = tryOneName(cfg, rname, qtype)
+ if err == nil {
+ return
+ }
+ return
+}
+
+// goLookupHost is the native Go implementation of LookupHost.
+// Used only if cgoLookupHost refuses to handle the request
+// (that is, only if cgoLookupHost is the stub in cgo_stub.go).
+// Normally we let cgo use the C library resolver instead of
+// depending on our lookup code, so that Go and C get the same
+// answers.
+func goLookupHost(name string) (addrs []string, err os.Error) {
+ // Use entries from /etc/hosts if they match.
+ addrs = lookupStaticHost(name)
+ if len(addrs) > 0 {
+ return
+ }
+ onceLoadConfig.Do(loadConfig)
+ if dnserr != nil || cfg == nil {
+ err = dnserr
+ return
+ }
+ ips, err := goLookupIP(name)
+ if err != nil {
+ return
+ }
+ addrs = make([]string, 0, len(ips))
+ for _, ip := range ips {
+ addrs = append(addrs, ip.String())
+ }
+ return
+}
+
+// goLookupIP is the native Go implementation of LookupIP.
+// Used only if cgoLookupIP refuses to handle the request
+// (that is, only if cgoLookupIP is the stub in cgo_stub.go).
+// Normally we let cgo use the C library resolver instead of
+// depending on our lookup code, so that Go and C get the same
+// answers.
+func goLookupIP(name string) (addrs []IP, err os.Error) {
+ onceLoadConfig.Do(loadConfig)
+ if dnserr != nil || cfg == nil {
+ err = dnserr
+ return
+ }
+ var records []dnsRR
+ var cname string
+ cname, records, err = lookup(name, dnsTypeA)
+ if err != nil {
+ return
+ }
+ addrs = convertRR_A(records)
+ if cname != "" {
+ name = cname
+ }
+ _, records, err = lookup(name, dnsTypeAAAA)
+ if err != nil && len(addrs) > 0 {
+ // Ignore error because A lookup succeeded.
+ err = nil
+ }
+ if err != nil {
+ return
+ }
+ addrs = append(addrs, convertRR_AAAA(records)...)
+ return
+}
+
+// goLookupCNAME is the native Go implementation of LookupCNAME.
+// Used only if cgoLookupCNAME refuses to handle the request
+// (that is, only if cgoLookupCNAME is the stub in cgo_stub.go).
+// Normally we let cgo use the C library resolver instead of
+// depending on our lookup code, so that Go and C get the same
+// answers.
+func goLookupCNAME(name string) (cname string, err os.Error) {
+ onceLoadConfig.Do(loadConfig)
+ if dnserr != nil || cfg == nil {
+ err = dnserr
+ return
+ }
+ _, rr, err := lookup(name, dnsTypeCNAME)
+ if err != nil {
+ return
+ }
+ cname = rr[0].(*dnsRR_CNAME).Cname
+ return
+}
diff --git a/src/pkg/net/dnsmsg.go b/src/pkg/net/dnsmsg.go
index 0ba69a0ce..ade1bb3a9 100644
--- a/src/pkg/net/dnsmsg.go
+++ b/src/pkg/net/dnsmsg.go
@@ -394,7 +394,6 @@ func packStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok bool)
f := val.Type().Field(i)
switch fv := val.Field(i); fv.Kind() {
default:
- BadType:
fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
return len(msg), false
case reflect.Struct:
@@ -419,7 +418,8 @@ func packStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok bool)
off += 4
case reflect.Array:
if fv.Type().Elem().Kind() != reflect.Uint8 {
- goto BadType
+ fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
+ return len(msg), false
}
n := fv.Len()
if off+n > len(msg) {
@@ -471,7 +471,6 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok boo
f := val.Type().Field(i)
switch fv := val.Field(i); fv.Kind() {
default:
- BadType:
fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
return len(msg), false
case reflect.Struct:
@@ -492,7 +491,8 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok boo
off += 4
case reflect.Array:
if fv.Type().Elem().Kind() != reflect.Uint8 {
- goto BadType
+ fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
+ return len(msg), false
}
n := fv.Len()
if off+n > len(msg) {
diff --git a/src/pkg/net/dnsmsg_test.go b/src/pkg/net/dnsmsg_test.go
index 20c9f02b0..06152a01a 100644
--- a/src/pkg/net/dnsmsg_test.go
+++ b/src/pkg/net/dnsmsg_test.go
@@ -6,14 +6,10 @@ package net
import (
"encoding/hex"
- "runtime"
"testing"
)
func TestDNSParseSRVReply(t *testing.T) {
- if runtime.GOOS == "windows" {
- return
- }
data, err := hex.DecodeString(dnsSRVReply)
if err != nil {
t.Fatal(err)
@@ -45,9 +41,6 @@ func TestDNSParseSRVReply(t *testing.T) {
}
func TestDNSParseCorruptSRVReply(t *testing.T) {
- if runtime.GOOS == "windows" {
- return
- }
data, err := hex.DecodeString(dnsSRVCorruptReply)
if err != nil {
t.Fatal(err)
diff --git a/src/pkg/net/dnsname_test.go b/src/pkg/net/dnsname_test.go
index 0c1a62518..70df693f7 100644
--- a/src/pkg/net/dnsname_test.go
+++ b/src/pkg/net/dnsname_test.go
@@ -6,7 +6,6 @@ package net
import (
"testing"
- "runtime"
)
type testCase struct {
@@ -55,9 +54,6 @@ func getTestCases(ch chan<- testCase) {
}
func TestDNSNames(t *testing.T) {
- if runtime.GOOS == "windows" {
- return
- }
ch := make(chan testCase)
go getTestCases(ch)
for tc := range ch {
diff --git a/src/pkg/net/fd_darwin.go b/src/pkg/net/fd_darwin.go
index 00a049bfd..7e3d549eb 100644
--- a/src/pkg/net/fd_darwin.go
+++ b/src/pkg/net/fd_darwin.go
@@ -56,7 +56,7 @@ func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, os.Error) {
return false, os.NewSyscallError("kevent", e)
}
if n != 1 || (ev.Flags&syscall.EV_ERROR) == 0 || int(ev.Ident) != fd || int(ev.Filter) != kmode {
- return false, os.ErrorString("kqueue phase error")
+ return false, os.NewError("kqueue phase error")
}
if ev.Data != 0 {
return false, os.Errno(int(ev.Data))
diff --git a/src/pkg/net/interface.go b/src/pkg/net/interface.go
index f622487ab..f6de36f64 100644
--- a/src/pkg/net/interface.go
+++ b/src/pkg/net/interface.go
@@ -34,7 +34,41 @@ type Interface struct {
MTU int // maximum transmission unit
Name string // e.g., "en0", "lo0", "eth0.100"
HardwareAddr HardwareAddr // IEEE MAC-48, EUI-48 and EUI-64 form
- rawFlags int
+ Flags Flags // e.g., FlagUp, FlagLoopback, FlagMulticast
+}
+
+type Flags uint
+
+const (
+ FlagUp Flags = 1 << iota // interface is up
+ FlagBroadcast // interface supports broadcast access capability
+ FlagLoopback // interface is a loopback interface
+ FlagPointToPoint // interface belongs to a point-to-point link
+ FlagMulticast // interface supports multicast access capability
+)
+
+var flagNames = []string{
+ "up",
+ "broadcast",
+ "loopback",
+ "pointtopoint",
+ "multicast",
+}
+
+func (f Flags) String() string {
+ s := ""
+ for i, name := range flagNames {
+ if f&(1<<uint(i)) != 0 {
+ if s != "" {
+ s += "|"
+ }
+ s += name
+ }
+ }
+ if s == "" {
+ s = "0"
+ }
+ return s
}
// Addrs returns interface addresses for a specific interface.
diff --git a/src/pkg/net/interface_bsd.go b/src/pkg/net/interface_bsd.go
index 141b95b38..a4c3e71fe 100644
--- a/src/pkg/net/interface_bsd.go
+++ b/src/pkg/net/interface_bsd.go
@@ -12,49 +12,6 @@ import (
"unsafe"
)
-// IsUp returns true if ifi is up.
-func (ifi *Interface) IsUp() bool {
- if ifi == nil {
- return false
- }
- return ifi.rawFlags&syscall.IFF_UP != 0
-}
-
-// IsLoopback returns true if ifi is a loopback interface.
-func (ifi *Interface) IsLoopback() bool {
- if ifi == nil {
- return false
- }
- return ifi.rawFlags&syscall.IFF_LOOPBACK != 0
-}
-
-// CanBroadcast returns true if ifi supports a broadcast access
-// capability.
-func (ifi *Interface) CanBroadcast() bool {
- if ifi == nil {
- return false
- }
- return ifi.rawFlags&syscall.IFF_BROADCAST != 0
-}
-
-// IsPointToPoint returns true if ifi belongs to a point-to-point
-// link.
-func (ifi *Interface) IsPointToPoint() bool {
- if ifi == nil {
- return false
- }
- return ifi.rawFlags&syscall.IFF_POINTOPOINT != 0
-}
-
-// CanMulticast returns true if ifi supports a multicast access
-// capability.
-func (ifi *Interface) CanMulticast() bool {
- if ifi == nil {
- return false
- }
- return ifi.rawFlags&syscall.IFF_MULTICAST != 0
-}
-
// If the ifindex is zero, interfaceTable returns mappings of all
// network interfaces. Otheriwse it returns a mapping of a specific
// interface.
@@ -106,7 +63,7 @@ func newLink(m *syscall.InterfaceMessage) ([]Interface, os.Error) {
// NOTE: SockaddrDatalink.Data is minimum work area,
// can be larger.
m.Data = m.Data[unsafe.Offsetof(v.Data):]
- ifi := Interface{Index: int(m.Header.Index), rawFlags: int(m.Header.Flags)}
+ ifi := Interface{Index: int(m.Header.Index), Flags: linkFlags(m.Header.Flags)}
var name [syscall.IFNAMSIZ]byte
for i := 0; i < int(v.Nlen); i++ {
name[i] = byte(m.Data[i])
@@ -125,6 +82,26 @@ func newLink(m *syscall.InterfaceMessage) ([]Interface, os.Error) {
return ift, nil
}
+func linkFlags(rawFlags int32) Flags {
+ var f Flags
+ if rawFlags&syscall.IFF_UP != 0 {
+ f |= FlagUp
+ }
+ if rawFlags&syscall.IFF_BROADCAST != 0 {
+ f |= FlagBroadcast
+ }
+ if rawFlags&syscall.IFF_LOOPBACK != 0 {
+ f |= FlagLoopback
+ }
+ if rawFlags&syscall.IFF_POINTOPOINT != 0 {
+ f |= FlagPointToPoint
+ }
+ if rawFlags&syscall.IFF_MULTICAST != 0 {
+ f |= FlagMulticast
+ }
+ return f
+}
+
// If the ifindex is zero, interfaceAddrTable returns addresses
// for all network interfaces. Otherwise it returns addresses
// for a specific interface.
diff --git a/src/pkg/net/interface_linux.go b/src/pkg/net/interface_linux.go
index 5c9657834..e869cd630 100644
--- a/src/pkg/net/interface_linux.go
+++ b/src/pkg/net/interface_linux.go
@@ -12,49 +12,6 @@ import (
"unsafe"
)
-// IsUp returns true if ifi is up.
-func (ifi *Interface) IsUp() bool {
- if ifi == nil {
- return false
- }
- return ifi.rawFlags&syscall.IFF_UP != 0
-}
-
-// IsLoopback returns true if ifi is a loopback interface.
-func (ifi *Interface) IsLoopback() bool {
- if ifi == nil {
- return false
- }
- return ifi.rawFlags&syscall.IFF_LOOPBACK != 0
-}
-
-// CanBroadcast returns true if ifi supports a broadcast access
-// capability.
-func (ifi *Interface) CanBroadcast() bool {
- if ifi == nil {
- return false
- }
- return ifi.rawFlags&syscall.IFF_BROADCAST != 0
-}
-
-// IsPointToPoint returns true if ifi belongs to a point-to-point
-// link.
-func (ifi *Interface) IsPointToPoint() bool {
- if ifi == nil {
- return false
- }
- return ifi.rawFlags&syscall.IFF_POINTOPOINT != 0
-}
-
-// CanMulticast returns true if ifi supports a multicast access
-// capability.
-func (ifi *Interface) CanMulticast() bool {
- if ifi == nil {
- return false
- }
- return ifi.rawFlags&syscall.IFF_MULTICAST != 0
-}
-
// If the ifindex is zero, interfaceTable returns mappings of all
// network interfaces. Otheriwse it returns a mapping of a specific
// interface.
@@ -98,7 +55,7 @@ done:
}
func newLink(attrs []syscall.NetlinkRouteAttr, ifim *syscall.IfInfomsg) Interface {
- ifi := Interface{Index: int(ifim.Index), rawFlags: int(ifim.Flags)}
+ ifi := Interface{Index: int(ifim.Index), Flags: linkFlags(ifim.Flags)}
for _, a := range attrs {
switch a.Attr.Type {
case syscall.IFLA_ADDRESS:
@@ -112,7 +69,7 @@ func newLink(attrs []syscall.NetlinkRouteAttr, ifim *syscall.IfInfomsg) Interfac
ifi.HardwareAddr = a.Value[:]
}
case syscall.IFLA_IFNAME:
- ifi.Name = string(a.Value[:])
+ ifi.Name = string(a.Value[:len(a.Value)-1])
case syscall.IFLA_MTU:
ifi.MTU = int(uint32(a.Value[3])<<24 | uint32(a.Value[2])<<16 | uint32(a.Value[1])<<8 | uint32(a.Value[0]))
}
@@ -120,6 +77,26 @@ func newLink(attrs []syscall.NetlinkRouteAttr, ifim *syscall.IfInfomsg) Interfac
return ifi
}
+func linkFlags(rawFlags uint32) Flags {
+ var f Flags
+ if rawFlags&syscall.IFF_UP != 0 {
+ f |= FlagUp
+ }
+ if rawFlags&syscall.IFF_BROADCAST != 0 {
+ f |= FlagBroadcast
+ }
+ if rawFlags&syscall.IFF_LOOPBACK != 0 {
+ f |= FlagLoopback
+ }
+ if rawFlags&syscall.IFF_POINTOPOINT != 0 {
+ f |= FlagPointToPoint
+ }
+ if rawFlags&syscall.IFF_MULTICAST != 0 {
+ f |= FlagMulticast
+ }
+ return f
+}
+
// If the ifindex is zero, interfaceAddrTable returns addresses
// for all network interfaces. Otherwise it returns addresses
// for a specific interface.
diff --git a/src/pkg/net/interface_stub.go b/src/pkg/net/interface_stub.go
index feb871bb5..24a7431c5 100644
--- a/src/pkg/net/interface_stub.go
+++ b/src/pkg/net/interface_stub.go
@@ -8,34 +8,6 @@ package net
import "os"
-// IsUp returns true if ifi is up.
-func (ifi *Interface) IsUp() bool {
- return false
-}
-
-// IsLoopback returns true if ifi is a loopback interface.
-func (ifi *Interface) IsLoopback() bool {
- return false
-}
-
-// CanBroadcast returns true if ifi supports a broadcast access
-// capability.
-func (ifi *Interface) CanBroadcast() bool {
- return false
-}
-
-// IsPointToPoint returns true if ifi belongs to a point-to-point
-// link.
-func (ifi *Interface) IsPointToPoint() bool {
- return false
-}
-
-// CanMulticast returns true if ifi supports a multicast access
-// capability.
-func (ifi *Interface) CanMulticast() bool {
- return false
-}
-
// If the ifindex is zero, interfaceTable returns mappings of all
// network interfaces. Otheriwse it returns a mapping of a specific
// interface.
diff --git a/src/pkg/net/interface_test.go b/src/pkg/net/interface_test.go
index 938434623..ac523a049 100644
--- a/src/pkg/net/interface_test.go
+++ b/src/pkg/net/interface_test.go
@@ -19,30 +19,6 @@ func sameInterface(i, j *Interface) bool {
return false
}
-func interfaceFlagsString(ifi *Interface) string {
- fs := "<"
- if ifi.IsUp() {
- fs += "UP,"
- }
- if ifi.CanBroadcast() {
- fs += "BROADCAST,"
- }
- if ifi.IsLoopback() {
- fs += "LOOPBACK,"
- }
- if ifi.IsPointToPoint() {
- fs += "POINTOPOINT,"
- }
- if ifi.CanMulticast() {
- fs += "MULTICAST,"
- }
- if len(fs) > 1 {
- fs = fs[:len(fs)-1]
- }
- fs += ">"
- return fs
-}
-
func TestInterfaces(t *testing.T) {
ift, err := Interfaces()
if err != nil {
@@ -69,11 +45,11 @@ func TestInterfaces(t *testing.T) {
if err != nil {
t.Fatalf("Interface.Addrs() failed: %v", err)
}
- t.Logf("%s: flags %s, ifindex %v, mtu %v\n", ifi.Name, interfaceFlagsString(&ifi), ifi.Index, ifi.MTU)
+ t.Logf("%q: flags %q, ifindex %v, mtu %v\n", ifi.Name, ifi.Flags.String(), ifi.Index, ifi.MTU)
for _, ifa := range ifat {
- t.Logf("\tinterface address %s\n", ifa.String())
+ t.Logf("\tinterface address %q\n", ifa.String())
}
- t.Logf("\thardware address %v", ifi.HardwareAddr.String())
+ t.Logf("\thardware address %q", ifi.HardwareAddr.String())
}
}
@@ -85,6 +61,6 @@ func TestInterfaceAddrs(t *testing.T) {
t.Logf("table: len/cap = %v/%v\n", len(ifat), cap(ifat))
for _, ifa := range ifat {
- t.Logf("interface address %s\n", ifa.String())
+ t.Logf("interface address %q\n", ifa.String())
}
}
diff --git a/src/pkg/net/interface_windows.go b/src/pkg/net/interface_windows.go
new file mode 100644
index 000000000..f54ffed70
--- /dev/null
+++ b/src/pkg/net/interface_windows.go
@@ -0,0 +1,152 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Network interface identification for Windows
+
+package net
+
+import (
+ "os"
+ "syscall"
+ "unsafe"
+)
+
+func bytePtrToString(p *uint8) string {
+ a := (*[10000]uint8)(unsafe.Pointer(p))
+ i := 0
+ for a[i] != 0 {
+ i++
+ }
+ return string(a[:i])
+}
+
+func getAdapterList() (*syscall.IpAdapterInfo, os.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 {
+ b = make([]byte, l)
+ a = (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0]))
+ e = syscall.GetAdaptersInfo(a, &l)
+ }
+ if e != 0 {
+ return nil, os.NewSyscallError("GetAdaptersInfo", e)
+ }
+ return a, nil
+}
+
+func getInterfaceList() ([]syscall.InterfaceInfo, os.Error) {
+ s, e := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP)
+ if e != 0 {
+ return nil, os.NewSyscallError("Socket", e)
+ }
+ defer syscall.Closesocket(int32(s))
+
+ ii := [20]syscall.InterfaceInfo{}
+ ret := uint32(0)
+ size := uint32(unsafe.Sizeof(ii))
+ e = syscall.WSAIoctl(int32(s), syscall.SIO_GET_INTERFACE_LIST, nil, 0, (*byte)(unsafe.Pointer(&ii[0])), size, &ret, nil, 0)
+ if e != 0 {
+ return nil, os.NewSyscallError("WSAIoctl", e)
+ }
+ c := ret / uint32(unsafe.Sizeof(ii[0]))
+ return ii[:c-1], nil
+}
+
+
+// If the ifindex is zero, interfaceTable returns mappings of all
+// network interfaces. Otheriwse it returns a mapping of a specific
+// interface.
+func interfaceTable(ifindex int) ([]Interface, os.Error) {
+ ai, e := getAdapterList()
+ if e != nil {
+ return nil, e
+ }
+
+ ii, e := getInterfaceList()
+ if e != nil {
+ return nil, e
+ }
+
+ var ift []Interface
+ for ; ai != nil; ai = ai.Next {
+ index := ai.Index
+ if ifindex == 0 || ifindex == int(index) {
+ var flags Flags
+
+ row := syscall.MibIfRow{Index: index}
+ e := syscall.GetIfEntry(&row)
+ if e != 0 {
+ return nil, os.NewSyscallError("GetIfEntry", e)
+ }
+
+ for _, ii := range ii {
+ ip := (*syscall.RawSockaddrInet4)(unsafe.Pointer(&ii.Address)).Addr
+ ipv4 := IPv4(ip[0], ip[1], ip[2], ip[3])
+ ipl := &ai.IpAddressList
+ for ipl != nil {
+ ips := bytePtrToString(&ipl.IpAddress.String[0])
+ if ipv4.Equal(parseIPv4(ips)) {
+ break
+ }
+ ipl = ipl.Next
+ }
+ if ipl == nil {
+ continue
+ }
+ if ii.Flags&syscall.IFF_UP != 0 {
+ flags |= FlagUp
+ }
+ if ii.Flags&syscall.IFF_LOOPBACK != 0 {
+ flags |= FlagLoopback
+ }
+ if ii.Flags&syscall.IFF_BROADCAST != 0 {
+ flags |= FlagBroadcast
+ }
+ if ii.Flags&syscall.IFF_POINTTOPOINT != 0 {
+ flags |= FlagPointToPoint
+ }
+ if ii.Flags&syscall.IFF_MULTICAST != 0 {
+ flags |= FlagMulticast
+ }
+ }
+
+ name := bytePtrToString(&ai.AdapterName[0])
+
+ ifi := Interface{
+ Index: int(index),
+ MTU: int(row.Mtu),
+ Name: name,
+ HardwareAddr: HardwareAddr(row.PhysAddr[:row.PhysAddrLen]),
+ Flags: flags}
+ ift = append(ift, ifi)
+ }
+ }
+ return ift, nil
+}
+
+// If the ifindex is zero, interfaceAddrTable returns addresses
+// for all network interfaces. Otherwise it returns addresses
+// for a specific interface.
+func interfaceAddrTable(ifindex int) ([]Addr, os.Error) {
+ ai, e := getAdapterList()
+ if e != nil {
+ return nil, e
+ }
+
+ var ifat []Addr
+ for ; ai != nil; ai = ai.Next {
+ index := ai.Index
+ if ifindex == 0 || ifindex == int(index) {
+ ipl := &ai.IpAddressList
+ for ; ipl != nil; ipl = ipl.Next {
+ ifa := IPAddr{}
+ ifa.IP = parseIPv4(bytePtrToString(&ipl.IpAddress.String[0]))
+ ifat = append(ifat, ifa.toAddr())
+ }
+ }
+ }
+ return ifat, nil
+}
diff --git a/src/pkg/net/iprawsock.go b/src/pkg/net/iprawsock.go
index a811027b1..43047a78e 100644
--- a/src/pkg/net/iprawsock.go
+++ b/src/pkg/net/iprawsock.go
@@ -294,7 +294,7 @@ func splitNetProto(netProto string) (net string, proto int, err os.Error) {
onceReadProtocols.Do(readProtocols)
i := last(netProto, ':')
if i < 0 { // no colon
- return "", 0, os.ErrorString("no IP protocol specified")
+ return "", 0, os.NewError("no IP protocol specified")
}
net = netProto[0:i]
protostr := netProto[i+1:]
diff --git a/src/pkg/net/ipsock.go b/src/pkg/net/ipsock.go
index 0b8c388f1..5d56520a9 100644
--- a/src/pkg/net/ipsock.go
+++ b/src/pkg/net/ipsock.go
@@ -270,12 +270,16 @@ func JoinHostPort(host, port string) string {
// Convert "host:port" into IP address and port.
func hostPortToIP(net, hostport string) (ip IP, iport int, err os.Error) {
+ var (
+ addr IP
+ p, i int
+ ok bool
+ )
host, port, err := SplitHostPort(hostport)
if err != nil {
goto Error
}
- var addr IP
if host != "" {
// Try as an IP address.
addr = ParseIP(host)
@@ -302,7 +306,7 @@ func hostPortToIP(net, hostport string) (ip IP, iport int, err os.Error) {
}
}
- 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 {
diff --git a/src/pkg/net/lookup.go b/src/pkg/net/lookup.go
deleted file mode 100644
index eeb22a8ae..000000000
--- a/src/pkg/net/lookup.go
+++ /dev/null
@@ -1,50 +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 net
-
-import (
- "os"
-)
-
-// LookupHost looks up the given host using the local resolver.
-// It returns an array of that host's addresses.
-func LookupHost(host string) (addrs []string, err os.Error) {
- addrs, err, ok := cgoLookupHost(host)
- if !ok {
- addrs, err = goLookupHost(host)
- }
- return
-}
-
-// LookupIP looks up host using the local resolver.
-// It returns an array of that host's IPv4 and IPv6 addresses.
-func LookupIP(host string) (addrs []IP, err os.Error) {
- addrs, err, ok := cgoLookupIP(host)
- if !ok {
- addrs, err = goLookupIP(host)
- }
- return
-}
-
-// LookupPort looks up the port for the given network and service.
-func LookupPort(network, service string) (port int, err os.Error) {
- port, err, ok := cgoLookupPort(network, service)
- if !ok {
- port, err = goLookupPort(network, service)
- }
- return
-}
-
-// LookupCNAME returns the canonical DNS host for the given name.
-// Callers that do not care about the canonical name can call
-// LookupHost or LookupIP directly; both take care of resolving
-// the canonical name as part of the lookup.
-func LookupCNAME(name string) (cname string, err os.Error) {
- cname, err, ok := cgoLookupCNAME(name)
- if !ok {
- cname, err = goLookupCNAME(name)
- }
- return
-}
diff --git a/src/pkg/net/lookup_unix.go b/src/pkg/net/lookup_unix.go
new file mode 100644
index 000000000..168d3fa6d
--- /dev/null
+++ b/src/pkg/net/lookup_unix.go
@@ -0,0 +1,126 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "os"
+ "rand"
+ "sort"
+)
+
+// LookupHost looks up the given host using the local resolver.
+// It returns an array of that host's addresses.
+func LookupHost(host string) (addrs []string, err os.Error) {
+ addrs, err, ok := cgoLookupHost(host)
+ if !ok {
+ addrs, err = goLookupHost(host)
+ }
+ return
+}
+
+// LookupIP looks up host using the local resolver.
+// It returns an array of that host's IPv4 and IPv6 addresses.
+func LookupIP(host string) (addrs []IP, err os.Error) {
+ addrs, err, ok := cgoLookupIP(host)
+ if !ok {
+ addrs, err = goLookupIP(host)
+ }
+ return
+}
+
+// LookupPort looks up the port for the given network and service.
+func LookupPort(network, service string) (port int, err os.Error) {
+ port, err, ok := cgoLookupPort(network, service)
+ if !ok {
+ port, err = goLookupPort(network, service)
+ }
+ return
+}
+
+// LookupCNAME returns the canonical DNS host for the given name.
+// Callers that do not care about the canonical name can call
+// LookupHost or LookupIP directly; both take care of resolving
+// the canonical name as part of the lookup.
+func LookupCNAME(name string) (cname string, err os.Error) {
+ cname, err, ok := cgoLookupCNAME(name)
+ if !ok {
+ cname, err = goLookupCNAME(name)
+ }
+ return
+}
+
+// LookupSRV tries to resolve an SRV query of the given service,
+// protocol, and domain name, as specified in RFC 2782. In most cases
+// the proto argument can be the same as the corresponding
+// Addr.Network(). The returned records are sorted by priority
+// and randomized by weight within a priority.
+func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os.Error) {
+ target := "_" + service + "._" + proto + "." + name
+ var records []dnsRR
+ cname, records, err = lookup(target, dnsTypeSRV)
+ if err != nil {
+ return
+ }
+ addrs = make([]*SRV, len(records))
+ for i, rr := range records {
+ r := rr.(*dnsRR_SRV)
+ addrs[i] = &SRV{r.Target, r.Port, r.Priority, r.Weight}
+ }
+ sort.Sort(byPriorityWeight(addrs))
+ i := 0
+ for j := 1; j < len(addrs); j++ {
+ if addrs[i].Priority != addrs[j].Priority {
+ shuffleSRVByWeight(addrs[i:j])
+ i = j
+ }
+ }
+ shuffleSRVByWeight(addrs[i:len(addrs)])
+ return
+}
+
+// LookupMX returns the DNS MX records for the given domain name sorted by preference.
+func LookupMX(name string) (mx []*MX, err os.Error) {
+ _, rr, err := lookup(name, dnsTypeMX)
+ if err != nil {
+ return
+ }
+ mx = make([]*MX, len(rr))
+ for i := range rr {
+ r := rr[i].(*dnsRR_MX)
+ mx[i] = &MX{r.Mx, r.Pref}
+ }
+ // Shuffle the records to match RFC 5321 when sorted
+ for i := range mx {
+ j := rand.Intn(i + 1)
+ mx[i], mx[j] = mx[j], mx[i]
+ }
+ sort.Sort(byPref(mx))
+ return
+}
+
+// LookupAddr performs a reverse lookup for the given address, returning a list
+// of names mapping to that address.
+func LookupAddr(addr string) (name []string, err os.Error) {
+ name = lookupStaticAddr(addr)
+ if len(name) > 0 {
+ return
+ }
+ var arpa string
+ arpa, err = reverseaddr(addr)
+ if err != nil {
+ return
+ }
+ var records []dnsRR
+ _, records, err = lookup(arpa, dnsTypePTR)
+ if err != nil {
+ return
+ }
+ name = make([]string, len(records))
+ for i := range records {
+ r := records[i].(*dnsRR_PTR)
+ name[i] = r.Ptr
+ }
+ return
+}
diff --git a/src/pkg/net/resolv_windows.go b/src/pkg/net/lookup_windows.go
index f7c3f51be..16b37f56c 100644
--- a/src/pkg/net/resolv_windows.go
+++ b/src/pkg/net/lookup_windows.go
@@ -14,8 +14,8 @@ import (
var hostentLock sync.Mutex
var serventLock sync.Mutex
-func goLookupHost(name string) (addrs []string, err os.Error) {
- ips, err := goLookupIP(name)
+func LookupHost(name string) (addrs []string, err os.Error) {
+ ips, err := LookupIP(name)
if err != nil {
return
}
@@ -26,7 +26,7 @@ func goLookupHost(name string) (addrs []string, err os.Error) {
return
}
-func goLookupIP(name string) (addrs []IP, err os.Error) {
+func LookupIP(name string) (addrs []IP, err os.Error) {
hostentLock.Lock()
defer hostentLock.Unlock()
h, e := syscall.GetHostByName(name)
@@ -47,7 +47,23 @@ func goLookupIP(name string) (addrs []IP, err os.Error) {
return addrs, nil
}
-func goLookupCNAME(name string) (cname string, err os.Error) {
+func LookupPort(network, service string) (port int, err os.Error) {
+ switch network {
+ case "tcp4", "tcp6":
+ network = "tcp"
+ case "udp4", "udp6":
+ network = "udp"
+ }
+ serventLock.Lock()
+ defer serventLock.Unlock()
+ s, e := syscall.GetServByName(service, network)
+ if e != 0 {
+ return 0, os.NewSyscallError("GetServByName", e)
+ }
+ return int(syscall.Ntohs(s.Port)), nil
+}
+
+func LookupCNAME(name string) (cname string, err os.Error) {
var r *syscall.DNSRecord
e := syscall.DnsQuery(name, syscall.DNS_TYPE_CNAME, 0, nil, &r, nil)
if int(e) != 0 {
@@ -61,13 +77,6 @@ func goLookupCNAME(name string) (cname string, err os.Error) {
return
}
-type SRV struct {
- Target string
- Port uint16
- Priority uint16
- Weight uint16
-}
-
func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os.Error) {
var r *syscall.DNSRecord
target := "_" + service + "._" + proto + "." + name
@@ -87,55 +96,12 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os.
return name, addrs, nil
}
-func goLookupPort(network, service string) (port int, err os.Error) {
- switch network {
- case "tcp4", "tcp6":
- network = "tcp"
- case "udp4", "udp6":
- network = "udp"
- }
- serventLock.Lock()
- defer serventLock.Unlock()
- s, e := syscall.GetServByName(service, network)
- if e != 0 {
- return 0, os.NewSyscallError("GetServByName", e)
- }
- return int(syscall.Ntohs(s.Port)), nil
-}
+// TODO(brainman): implement LookupMX and LookupAddr.
-// TODO(brainman): Following code is only to get tests running.
-
-func isDomainName(s string) bool {
- panic("unimplemented")
-}
-
-func reverseaddr(addr string) (arpa string, err os.Error) {
- panic("unimplemented")
-}
-
-func answer(name, server string, dns *dnsMsg, qtype uint16) (cname string, addrs []dnsRR, err os.Error) {
- panic("unimplemented")
+func LookupMX(name string) (mx []*MX, err os.Error) {
+ return nil, os.NewSyscallError("LookupMX", syscall.EWINDOWS)
}
-// DNSError represents a DNS lookup error.
-type DNSError struct {
- Error string // description of the error
- Name string // name looked for
- Server string // server used
- IsTimeout bool
+func LookupAddr(addr string) (name []string, err os.Error) {
+ return nil, os.NewSyscallError("LookupAddr", syscall.EWINDOWS)
}
-
-func (e *DNSError) String() string {
- if e == nil {
- return "<nil>"
- }
- s := "lookup " + e.Name
- if e.Server != "" {
- s += " on " + e.Server
- }
- s += ": " + e.Error
- return s
-}
-
-func (e *DNSError) Timeout() bool { return e.IsTimeout }
-func (e *DNSError) Temporary() bool { return e.IsTimeout }
diff --git a/src/pkg/net/net.go b/src/pkg/net/net.go
index 51db10739..5c84d3434 100644
--- a/src/pkg/net/net.go
+++ b/src/pkg/net/net.go
@@ -115,7 +115,7 @@ type Listener interface {
Addr() Addr
}
-var errMissingAddress = os.ErrorString("missing address")
+var errMissingAddress = os.NewError("missing address")
type OpError struct {
Op string
diff --git a/src/pkg/net/net_test.go b/src/pkg/net/net_test.go
index f7eae56fe..698a84527 100644
--- a/src/pkg/net/net_test.go
+++ b/src/pkg/net/net_test.go
@@ -7,7 +7,6 @@ package net
import (
"flag"
"regexp"
- "runtime"
"testing"
)
@@ -103,9 +102,6 @@ var revAddrTests = []struct {
}
func TestReverseAddress(t *testing.T) {
- if runtime.GOOS == "windows" {
- return
- }
for i, tt := range revAddrTests {
a, e := reverseaddr(tt.Addr)
if len(tt.ErrPrefix) > 0 && e == nil {
diff --git a/src/pkg/net/newpollserver.go b/src/pkg/net/newpollserver.go
index fff54dba7..427208701 100644
--- a/src/pkg/net/newpollserver.go
+++ b/src/pkg/net/newpollserver.go
@@ -18,12 +18,7 @@ func newPollServer() (s *pollServer, err os.Error) {
}
var e int
if e = syscall.SetNonblock(s.pr.Fd(), true); e != 0 {
- Errno:
- err = &os.PathError{"setnonblock", s.pr.Name(), os.Errno(e)}
- Error:
- s.pr.Close()
- s.pw.Close()
- return nil, err
+ goto Errno
}
if e = syscall.SetNonblock(s.pw.Fd(), true); e != 0 {
goto Errno
@@ -38,4 +33,11 @@ func newPollServer() (s *pollServer, err os.Error) {
s.pending = make(map[int]*netFD)
go s.Run()
return s, nil
+
+Errno:
+ err = &os.PathError{"setnonblock", s.pr.Name(), os.Errno(e)}
+Error:
+ s.pr.Close()
+ s.pw.Close()
+ return nil, err
}
diff --git a/src/pkg/net/sendfile_windows.go b/src/pkg/net/sendfile_windows.go
new file mode 100644
index 000000000..34abc5490
--- /dev/null
+++ b/src/pkg/net/sendfile_windows.go
@@ -0,0 +1,68 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "io"
+ "os"
+ "syscall"
+)
+
+type sendfileOp struct {
+ anOp
+ src int32 // source
+ n uint32
+}
+
+func (o *sendfileOp) Submit() (errno int) {
+ return syscall.TransmitFile(int32(o.fd.sysfd), o.src, o.n, 0, &o.o, nil, syscall.TF_WRITE_BEHIND)
+}
+
+func (o *sendfileOp) Name() string {
+ return "TransmitFile"
+}
+
+// sendFile copies the contents of r to c using the TransmitFile
+// system call to minimize copies.
+//
+// if handled == true, sendFile returns the number of bytes copied and any
+// non-EOF error.
+//
+// if handled == false, sendFile performed no work.
+//
+// Note that sendfile for windows does not suppport >2GB file.
+func sendFile(c *netFD, r io.Reader) (written int64, err os.Error, handled bool) {
+ var n int64 = 0 // by default, copy until EOF
+
+ lr, ok := r.(*io.LimitedReader)
+ if ok {
+ n, r = lr.N, lr.R
+ if n <= 0 {
+ return 0, nil, true
+ }
+ }
+ f, ok := r.(*os.File)
+ if !ok {
+ return 0, nil, false
+ }
+
+ c.wio.Lock()
+ defer c.wio.Unlock()
+ c.incref()
+ defer c.decref()
+
+ var o sendfileOp
+ o.Init(c)
+ o.n = uint32(n)
+ o.src = int32(f.Fd())
+ done, err := iosrv.ExecIO(&o, 0)
+ if err != nil {
+ return 0, err, false
+ }
+ if lr != nil {
+ lr.N -= int64(done)
+ }
+ return int64(done), nil, true
+}
diff --git a/src/pkg/net/udpsock.go b/src/pkg/net/udpsock.go
index 5469acffa..94e249d62 100644
--- a/src/pkg/net/udpsock.go
+++ b/src/pkg/net/udpsock.go
@@ -281,7 +281,7 @@ func (c *UDPConn) BindToDevice(device string) os.Error {
// Closing c does not affect f, and closing f does not affect c.
func (c *UDPConn) File() (f *os.File, err os.Error) { return c.fd.dup() }
-var errInvalidMulticast = os.ErrorString("invalid IPv4 multicast address")
+var errInvalidMulticast = os.NewError("invalid IPv4 multicast address")
// JoinGroup joins the IPv4 multicast group named by addr.
// The UDPConn must use the "udp4" network.
diff --git a/src/pkg/netchan/common.go b/src/pkg/netchan/common.go
index a319391bf..ac1ca12f5 100644
--- a/src/pkg/netchan/common.go
+++ b/src/pkg/netchan/common.go
@@ -153,7 +153,7 @@ func (cs *clientSet) drain(timeout int64) os.Error {
break
}
if timeout > 0 && time.Nanoseconds()-startTime >= timeout {
- return os.ErrorString("timeout")
+ return os.NewError("timeout")
}
time.Sleep(100 * 1e6) // 100 milliseconds
}
@@ -186,7 +186,7 @@ func (cs *clientSet) sync(timeout int64) os.Error {
break
}
if timeout > 0 && time.Nanoseconds()-startTime >= timeout {
- return os.ErrorString("timeout")
+ return os.NewError("timeout")
}
time.Sleep(100 * 1e6) // 100 milliseconds
}
diff --git a/src/pkg/netchan/export.go b/src/pkg/netchan/export.go
index 1e5ccdb5c..7df736515 100644
--- a/src/pkg/netchan/export.go
+++ b/src/pkg/netchan/export.go
@@ -343,20 +343,20 @@ func (exp *Exporter) Sync(timeout int64) os.Error {
func checkChan(chT interface{}, dir Dir) (reflect.Value, os.Error) {
chanType := reflect.TypeOf(chT)
if chanType.Kind() != reflect.Chan {
- return reflect.Value{}, os.ErrorString("not a channel")
+ return reflect.Value{}, os.NewError("not a channel")
}
if dir != Send && dir != Recv {
- return reflect.Value{}, os.ErrorString("unknown channel direction")
+ return reflect.Value{}, os.NewError("unknown channel direction")
}
switch chanType.ChanDir() {
case reflect.BothDir:
case reflect.SendDir:
if dir != Recv {
- return reflect.Value{}, os.ErrorString("to import/export with Send, must provide <-chan")
+ return reflect.Value{}, os.NewError("to import/export with Send, must provide <-chan")
}
case reflect.RecvDir:
if dir != Send {
- return reflect.Value{}, os.ErrorString("to import/export with Recv, must provide chan<-")
+ return reflect.Value{}, os.NewError("to import/export with Recv, must provide chan<-")
}
}
return reflect.ValueOf(chT), nil
@@ -376,7 +376,7 @@ func (exp *Exporter) Export(name string, chT interface{}, dir Dir) os.Error {
defer exp.mu.Unlock()
_, present := exp.names[name]
if present {
- return os.ErrorString("channel name already being exported:" + name)
+ return os.NewError("channel name already being exported:" + name)
}
exp.names[name] = &chanDir{ch, dir}
return nil
@@ -393,7 +393,7 @@ func (exp *Exporter) Hangup(name string) os.Error {
// TODO drop all instances of channel from client sets
exp.mu.Unlock()
if !ok {
- return os.ErrorString("netchan export: hangup: no such channel: " + name)
+ return os.NewError("netchan export: hangup: no such channel: " + name)
}
chDir.ch.Close()
return nil
diff --git a/src/pkg/netchan/import.go b/src/pkg/netchan/import.go
index 7d96228c4..ec17d9777 100644
--- a/src/pkg/netchan/import.go
+++ b/src/pkg/netchan/import.go
@@ -102,7 +102,7 @@ func (imp *Importer) run() {
if err.Error != "" {
impLog("response error:", err.Error)
select {
- case imp.errors <- os.ErrorString(err.Error):
+ case imp.errors <- os.NewError(err.Error):
continue // errors are not acknowledged
default:
imp.shutdown()
@@ -203,7 +203,7 @@ func (imp *Importer) ImportNValues(name string, chT interface{}, dir Dir, size,
defer imp.chanLock.Unlock()
_, present := imp.names[name]
if present {
- return os.ErrorString("channel name already being imported:" + name)
+ return os.NewError("channel name already being imported:" + name)
}
if size < 1 {
size = 1
@@ -254,7 +254,7 @@ func (imp *Importer) Hangup(name string) os.Error {
defer imp.chanLock.Unlock()
nc := imp.names[name]
if nc == nil {
- return os.ErrorString("netchan import: hangup: no such channel: " + name)
+ return os.NewError("netchan import: hangup: no such channel: " + name)
}
imp.names[name] = nil, false
imp.chans[nc.id] = nil, false
@@ -279,7 +279,7 @@ func (imp *Importer) Drain(timeout int64) os.Error {
startTime := time.Nanoseconds()
for imp.unackedCount() > 0 {
if timeout > 0 && time.Nanoseconds()-startTime >= timeout {
- return os.ErrorString("timeout")
+ return os.NewError("timeout")
}
time.Sleep(100 * 1e6)
}
diff --git a/src/pkg/os/Makefile b/src/pkg/os/Makefile
index 497e5a958..060cc970d 100644
--- a/src/pkg/os/Makefile
+++ b/src/pkg/os/Makefile
@@ -73,6 +73,7 @@ GOFILES_plan9=\
path_plan9.go\
sys_plan9.go\
exec_plan9.go\
+ str.go\
GOFILES+=$(GOFILES_$(GOOS))
diff --git a/src/pkg/os/error.go b/src/pkg/os/error.go
index 2c4516ca7..b4511dd2f 100644
--- a/src/pkg/os/error.go
+++ b/src/pkg/os/error.go
@@ -9,20 +9,17 @@ type Error interface {
String() string
}
-// A helper type that can be embedded or wrapped to simplify satisfying
-// Error.
-type ErrorString string
+// // errorString is a helper type used by NewError.
+type errorString string
-func (e ErrorString) String() string { return string(e) }
-func (e ErrorString) Temporary() bool { return false }
-func (e ErrorString) Timeout() bool { return false }
+func (e errorString) String() string { return string(e) }
// Note: If the name of the function NewError changes,
// pkg/go/doc/doc.go should be adjusted since it hardwires
// this name in a heuristic.
-// NewError converts s to an ErrorString, which satisfies the Error interface.
-func NewError(s string) Error { return ErrorString(s) }
+// // NewError returns a new error with error.String() == s.
+func NewError(s string) Error { return errorString(s) }
// PathError records an error and the operation and file path that caused it.
type PathError struct {
diff --git a/src/pkg/os/error_plan9.go b/src/pkg/os/error_plan9.go
index 3374775b8..cacfc150c 100644
--- a/src/pkg/os/error_plan9.go
+++ b/src/pkg/os/error_plan9.go
@@ -45,6 +45,7 @@ var (
EEXIST = Eexist
EIO = Eio
EACCES = Eperm
+ EPERM = Eperm
EISDIR = syscall.EISDIR
ENAMETOOLONG = NewError("file name too long")
diff --git a/src/pkg/os/exec.go b/src/pkg/os/exec.go
index f62caf9a0..e2234f14a 100644
--- a/src/pkg/os/exec.go
+++ b/src/pkg/os/exec.go
@@ -37,6 +37,12 @@ type ProcAttr struct {
// depending on the underlying operating system. A nil entry corresponds
// to that file being closed when the process starts.
Files []*File
+
+ // Operating system-specific process creation attributes.
+ // Note that setting this field means that your program
+ // may not execute properly or even compile on some
+ // operating systems.
+ Sys *syscall.SysProcAttr
}
// Getpid returns the process id of the caller.
diff --git a/src/pkg/os/exec_plan9.go b/src/pkg/os/exec_plan9.go
index 11874aba6..2590dd67d 100644
--- a/src/pkg/os/exec_plan9.go
+++ b/src/pkg/os/exec_plan9.go
@@ -15,6 +15,7 @@ func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err E
sysattr := &syscall.ProcAttr{
Dir: attr.Dir,
Env: attr.Env,
+ Sys: attr.Sys,
}
// Create array of integer (system) fds.
@@ -37,6 +38,17 @@ func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err E
return newProcess(pid, h), nil
}
+// Kill causes the Process to exit immediately.
+func (p *Process) Kill() Error {
+ f, e := OpenFile("/proc/"+itoa(p.Pid)+"/ctl", O_WRONLY, 0)
+ if iserror(e) {
+ return NewSyscallError("kill", e)
+ }
+ defer f.Close()
+ _, e = f.Write([]byte("kill"))
+ return e
+}
+
// Exec replaces the current process with an execution of the
// named binary, with arguments argv and environment envv.
// If successful, Exec never returns. If it fails, it returns an Error.
@@ -51,7 +63,9 @@ func Exec(name string, argv []string, envv []string) Error {
}
// Waitmsg stores the information about an exited process as reported by Wait.
-type Waitmsg syscall.Waitmsg
+type Waitmsg struct {
+ syscall.Waitmsg
+}
// Wait waits for the Process to exit or stop, and then returns a
// Waitmsg describing its status and an Error, if any. The options
@@ -75,7 +89,7 @@ func (p *Process) Wait(options int) (w *Waitmsg, err Error) {
}
}
- return (*Waitmsg)(&waitmsg), nil
+ return &Waitmsg{waitmsg}, nil
}
// Wait waits for process pid to exit or stop, and then returns a
@@ -109,6 +123,9 @@ func FindProcess(pid int) (p *Process, err Error) {
return newProcess(pid, 0), nil
}
-func (w Waitmsg) String() string {
+func (w *Waitmsg) String() string {
+ if w == nil {
+ return "<nil>"
+ }
return "exit status: " + w.Msg
}
diff --git a/src/pkg/os/exec_posix.go b/src/pkg/os/exec_posix.go
index bf992ef42..7dfcdd486 100644
--- a/src/pkg/os/exec_posix.go
+++ b/src/pkg/os/exec_posix.go
@@ -30,6 +30,7 @@ func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err E
sysattr := &syscall.ProcAttr{
Dir: attr.Dir,
Env: attr.Env,
+ Sys: attr.Sys,
}
if sysattr.Env == nil {
sysattr.Env = Environ()
@@ -127,7 +128,10 @@ func itod(i int) string {
return string(b[bp:])
}
-func (w Waitmsg) String() string {
+func (w *Waitmsg) String() string {
+ if w == nil {
+ return "<nil>"
+ }
// TODO(austin) Use signal names when possible?
res := ""
switch {
diff --git a/src/pkg/os/exec_windows.go b/src/pkg/os/exec_windows.go
index bac33b908..991099d4f 100644
--- a/src/pkg/os/exec_windows.go
+++ b/src/pkg/os/exec_windows.go
@@ -17,7 +17,7 @@ func (p *Process) Wait(options int) (w *Waitmsg, err Error) {
case syscall.WAIT_FAILED:
return nil, NewSyscallError("WaitForSingleObject", e)
default:
- return nil, ErrorString("os: unexpected result from WaitForSingleObject")
+ return nil, NewError("os: unexpected result from WaitForSingleObject")
}
var ec uint32
e = syscall.GetExitCodeProcess(int32(p.handle), &ec)
diff --git a/src/pkg/os/file.go b/src/pkg/os/file.go
index dff8fa862..0e97e0bd9 100644
--- a/src/pkg/os/file.go
+++ b/src/pkg/os/file.go
@@ -4,6 +4,8 @@
// Package os provides a platform-independent interface to operating system
// functionality. The design is Unix-like.
+// The os interface is intended to be uniform across all operating systems.
+// Features not generally available appear in the system-specific package syscall.
package os
import (
diff --git a/src/pkg/os/file_plan9.go b/src/pkg/os/file_plan9.go
index 7b473f802..b0c42d14d 100644
--- a/src/pkg/os/file_plan9.go
+++ b/src/pkg/os/file_plan9.go
@@ -30,14 +30,43 @@ const DevNull = "/dev/null"
// methods on the returned File can be used for I/O.
// It returns the File and an Error, if any.
func OpenFile(name string, flag int, perm uint32) (file *File, err Error) {
- var fd int
- var e syscall.Error
+ var (
+ fd int
+ e syscall.Error
+ create bool
+ excl bool
+ trunc bool
+ append bool
+ )
- syscall.ForkLock.RLock()
if flag&O_CREATE == O_CREATE {
- fd, e = syscall.Create(name, flag & ^O_CREATE, perm)
+ flag = flag & ^O_CREATE
+ create = true
+ }
+ if flag&O_EXCL == O_EXCL {
+ excl = true
+ }
+ if flag&O_TRUNC == O_TRUNC {
+ trunc = true
+ }
+ // O_APPEND is emulated on Plan 9
+ if flag&O_APPEND == O_APPEND {
+ flag = flag &^ O_APPEND
+ append = true
+ }
+
+ syscall.ForkLock.RLock()
+ if (create && trunc) || excl {
+ fd, e = syscall.Create(name, flag, perm)
} else {
fd, e = syscall.Open(name, flag)
+ if e != nil && create {
+ var e1 syscall.Error
+ fd, e1 = syscall.Create(name, flag, perm)
+ if e1 == nil {
+ e = nil
+ }
+ }
}
syscall.ForkLock.RUnlock()
@@ -45,6 +74,12 @@ func OpenFile(name string, flag int, perm uint32) (file *File, err Error) {
return nil, &PathError{"open", name, e}
}
+ if append {
+ if _, e = syscall.Seek(fd, 0, SEEK_END); e != nil {
+ return nil, &PathError{"seek", name, e}
+ }
+ }
+
return NewFile(fd, name), nil
}
@@ -69,8 +104,12 @@ func (file *File) Close() Error {
// Stat returns the FileInfo structure describing file.
// It returns the FileInfo and an error, if any.
-func (file *File) Stat() (fi *FileInfo, err Error) {
- return dirstat(file)
+func (f *File) Stat() (fi *FileInfo, err Error) {
+ d, err := dirstat(f)
+ if iserror(err) {
+ return nil, err
+ }
+ return fileInfoFromStat(new(FileInfo), d), err
}
// Truncate changes the size of the file.
@@ -90,10 +129,15 @@ func (f *File) Truncate(size int64) Error {
// Chmod changes the mode of the file to mode.
func (f *File) Chmod(mode uint32) Error {
var d Dir
- d.Null()
+ var mask = ^uint32(0777)
- d.Mode = mode & 0777
+ d.Null()
+ odir, e := dirstat(f)
+ if iserror(e) {
+ return &PathError{"chmod", f.name, e}
+ }
+ d.Mode = (odir.Mode & mask) | (mode &^ mask)
if e := syscall.Fwstat(f.fd, pdir(nil, &d)); iserror(e) {
return &PathError{"chmod", f.name, e}
}
@@ -188,10 +232,15 @@ func Rename(oldname, newname string) Error {
// Chmod changes the mode of the named file to mode.
func Chmod(name string, mode uint32) Error {
var d Dir
- d.Null()
+ var mask = ^uint32(0777)
- d.Mode = mode & 0777
+ d.Null()
+ odir, e := dirstat(name)
+ if iserror(e) {
+ return &PathError{"chmod", name, e}
+ }
+ d.Mode = (odir.Mode & mask) | (mode &^ mask)
if e := syscall.Wstat(name, pdir(nil, &d)); iserror(e) {
return &PathError{"chmod", name, e}
}
diff --git a/src/pkg/os/os_test.go b/src/pkg/os/os_test.go
index 8eabdee6b..c22b536d5 100644
--- a/src/pkg/os/os_test.go
+++ b/src/pkg/os/os_test.go
@@ -359,8 +359,8 @@ func TestReaddirNValues(t *testing.T) {
}
func TestHardLink(t *testing.T) {
- // Hardlinks are not supported under windows.
- if syscall.OS == "windows" {
+ // Hardlinks are not supported under windows or Plan 9.
+ if syscall.OS == "windows" || syscall.OS == "plan9" {
return
}
from, to := "hardlinktestfrom", "hardlinktestto"
@@ -392,8 +392,8 @@ func TestHardLink(t *testing.T) {
}
func TestSymLink(t *testing.T) {
- // Symlinks are not supported under windows.
- if syscall.OS == "windows" {
+ // Symlinks are not supported under windows or Plan 9.
+ if syscall.OS == "windows" || syscall.OS == "plan9" {
return
}
from, to := "symlinktestfrom", "symlinktestto"
@@ -454,8 +454,8 @@ func TestSymLink(t *testing.T) {
}
func TestLongSymlink(t *testing.T) {
- // Symlinks are not supported under windows.
- if syscall.OS == "windows" {
+ // Symlinks are not supported under windows or Plan 9.
+ if syscall.OS == "windows" || syscall.OS == "plan9" {
return
}
s := "0123456789abcdef"
@@ -588,8 +588,9 @@ func checkUidGid(t *testing.T, path string, uid, gid int) {
}
func TestChown(t *testing.T) {
- // Chown is not supported under windows.
- if syscall.OS == "windows" {
+ // Chown is not supported under windows or Plan 9.
+ // Plan9 provides a native ChownPlan9 version instead.
+ if syscall.OS == "windows" || syscall.OS == "plan9" {
return
}
// Use TempDir() to make sure we're on a local file system,
@@ -708,7 +709,11 @@ func TestChtimes(t *testing.T) {
t.Fatalf("second Stat %s: %s", f.Name(), err)
}
- if postStat.Atime_ns >= preStat.Atime_ns {
+ /* Plan 9:
+ Mtime is the time of the last change of content. Similarly, atime is set whenever the
+ contents are accessed; also, it is set whenever mtime is set.
+ */
+ if postStat.Atime_ns >= preStat.Atime_ns && syscall.OS != "plan9" {
t.Errorf("Atime_ns didn't go backwards; was=%d, after=%d",
preStat.Atime_ns,
postStat.Atime_ns)
@@ -733,6 +738,10 @@ func TestChdirAndGetwd(t *testing.T) {
// These are chosen carefully not to be symlinks on a Mac
// (unlike, say, /var, /etc, and /tmp).
dirs := []string{"/", "/usr/bin"}
+ // /usr/bin does not usually exist on Plan 9.
+ if syscall.OS == "plan9" {
+ dirs = []string{"/", "/usr"}
+ }
for mode := 0; mode < 2; mode++ {
for _, d := range dirs {
if mode == 0 {
@@ -858,7 +867,15 @@ func TestOpenError(t *testing.T) {
t.Errorf("Open(%q, %d) returns error of %T type; want *os.PathError", tt.path, tt.mode, err)
}
if perr.Error != tt.error {
- t.Errorf("Open(%q, %d) = _, %q; want %q", tt.path, tt.mode, perr.Error.String(), tt.error.String())
+ if syscall.OS == "plan9" {
+ syscallErrStr := perr.Error.String()
+ expectedErrStr := strings.Replace(tt.error.String(), "file ", "", 1)
+ if !strings.HasSuffix(syscallErrStr, expectedErrStr) {
+ t.Errorf("Open(%q, %d) = _, %q; want suffix %q", tt.path, tt.mode, syscallErrStr, expectedErrStr)
+ }
+ } else {
+ t.Errorf("Open(%q, %d) = _, %q; want %q", tt.path, tt.mode, perr.Error.String(), tt.error.String())
+ }
}
}
}
@@ -893,7 +910,8 @@ func run(t *testing.T, cmd []string) string {
func TestHostname(t *testing.T) {
// There is no other way to fetch hostname on windows, but via winapi.
- if syscall.OS == "windows" {
+ // On Plan 9 it is can be taken from #c/sysname as Hostname() does.
+ if syscall.OS == "windows" || syscall.OS == "plan9" {
return
}
// Check internal Hostname() against the output of /bin/hostname.
@@ -1024,3 +1042,11 @@ func TestStatDirWithTrailingSlash(t *testing.T) {
t.Fatal("stat failed:", err)
}
}
+
+func TestNilWaitmsgString(t *testing.T) {
+ var w *Waitmsg
+ s := w.String()
+ if s != "<nil>" {
+ t.Errorf("(*Waitmsg)(nil).String() = %q, want %q", s, "<nil>")
+ }
+}
diff --git a/src/pkg/os/path_test.go b/src/pkg/os/path_test.go
index d58945aab..31acbaa43 100644
--- a/src/pkg/os/path_test.go
+++ b/src/pkg/os/path_test.go
@@ -166,8 +166,8 @@ func TestRemoveAll(t *testing.T) {
}
func TestMkdirAllWithSymlink(t *testing.T) {
- if runtime.GOOS == "windows" {
- t.Log("Skipping test: symlinks don't exist under Windows")
+ if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+ t.Log("Skipping test: symlinks don't exist under Windows/Plan 9")
return
}
@@ -191,7 +191,7 @@ func TestMkdirAllWithSymlink(t *testing.T) {
}
func TestMkdirAllAtSlash(t *testing.T) {
- if runtime.GOOS == "windows" {
+ if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
return
}
RemoveAll("/_go_os_test")
diff --git a/src/pkg/os/path_windows.go b/src/pkg/os/path_windows.go
index 8740a9e61..61f2ca59f 100644
--- a/src/pkg/os/path_windows.go
+++ b/src/pkg/os/path_windows.go
@@ -6,7 +6,7 @@ package os
const (
PathSeparator = '\\' // OS-specific path separator
- PathListSeparator = ':' // OS-specific path list separator
+ PathListSeparator = ';' // OS-specific path list separator
)
// IsPathSeparator returns true if c is a directory separator character.
diff --git a/src/pkg/os/stat_plan9.go b/src/pkg/os/stat_plan9.go
index e96749d33..d2300d598 100644
--- a/src/pkg/os/stat_plan9.go
+++ b/src/pkg/os/stat_plan9.go
@@ -26,7 +26,7 @@ func fileInfoFromStat(fi *FileInfo, d *Dir) *FileInfo {
}
// arg is an open *File or a path string.
-func dirstat(arg interface{}) (fi *FileInfo, err Error) {
+func dirstat(arg interface{}) (d *Dir, err Error) {
var name string
nd := syscall.STATFIXLEN + 16*4
@@ -62,8 +62,7 @@ func dirstat(arg interface{}) (fi *FileInfo, err Error) {
if e != nil {
return nil, &PathError{"stat", name, e}
}
-
- return fileInfoFromStat(new(FileInfo), d), nil
+ return d, e
}
}
@@ -73,12 +72,20 @@ func dirstat(arg interface{}) (fi *FileInfo, err Error) {
// Stat returns a FileInfo structure describing the named file and an error, if any.
func Stat(name string) (fi *FileInfo, err Error) {
- return dirstat(name)
+ d, err := dirstat(name)
+ if iserror(err) {
+ return nil, err
+ }
+ return fileInfoFromStat(new(FileInfo), d), err
}
// Lstat returns the FileInfo structure describing the named file and an
// error, if any. If the file is a symbolic link (though Plan 9 does not have symbolic links),
// the returned FileInfo describes the symbolic link. Lstat makes no attempt to follow the link.
func Lstat(name string) (fi *FileInfo, err Error) {
- return dirstat(name)
+ d, err := dirstat(name)
+ if iserror(err) {
+ return nil, err
+ }
+ return fileInfoFromStat(new(FileInfo), d), err
}
diff --git a/src/pkg/os/str.go b/src/pkg/os/str.go
new file mode 100644
index 000000000..8dc9e4747
--- /dev/null
+++ b/src/pkg/os/str.go
@@ -0,0 +1,20 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+func itoa(val int) string { // do it here rather than with fmt to avoid dependency
+ if val < 0 {
+ return "-" + itoa(-val)
+ }
+ var buf [32]byte // big enough for int64
+ i := len(buf) - 1
+ for val >= 10 {
+ buf[i] = byte(val%10 + '0')
+ i--
+ val /= 10
+ }
+ buf[i] = byte(val + '0')
+ return string(buf[i:])
+}
diff --git a/src/pkg/patch/textdiff.go b/src/pkg/patch/textdiff.go
index c7e693fc6..482bd6781 100644
--- a/src/pkg/patch/textdiff.go
+++ b/src/pkg/patch/textdiff.go
@@ -17,6 +17,8 @@ type TextChunk struct {
}
func ParseTextDiff(raw []byte) (TextDiff, os.Error) {
+ var chunkHeader []byte
+
// Copy raw so it is safe to keep references to slices.
_, chunks := sections(raw, "@@ -")
delta := 0
@@ -26,13 +28,12 @@ func ParseTextDiff(raw []byte) (TextDiff, os.Error) {
// Parse start line: @@ -oldLine,oldCount +newLine,newCount @@ junk
chunk := splitLines(raw)
- chunkHeader := chunk[0]
+ chunkHeader = chunk[0]
var ok bool
var oldLine, oldCount, newLine, newCount int
s := chunkHeader
if oldLine, s, ok = atoi(s, "@@ -", 10); !ok {
- ErrChunkHdr:
- return nil, SyntaxError("unexpected chunk header line: " + string(chunkHeader))
+ goto ErrChunkHdr
}
if len(s) == 0 || s[0] != ',' {
oldCount = 1
@@ -145,6 +146,9 @@ func ParseTextDiff(raw []byte) (TextDiff, os.Error) {
}
}
return diff, nil
+
+ErrChunkHdr:
+ return nil, SyntaxError("unexpected chunk header line: " + string(chunkHeader))
}
var ErrPatchFailure = os.NewError("patch did not apply cleanly")
diff --git a/src/pkg/rand/rand_test.go b/src/pkg/rand/rand_test.go
index a689da848..3ebc1141d 100644
--- a/src/pkg/rand/rand_test.go
+++ b/src/pkg/rand/rand_test.go
@@ -45,12 +45,12 @@ func (this *statsResults) checkSimilarDistribution(expected *statsResults) os.Er
if !nearEqual(this.mean, expected.mean, expected.closeEnough, expected.maxError) {
s := fmt.Sprintf("mean %v != %v (allowed error %v, %v)", this.mean, expected.mean, expected.closeEnough, expected.maxError)
fmt.Println(s)
- return os.ErrorString(s)
+ return os.NewError(s)
}
if !nearEqual(this.stddev, expected.stddev, 0, expected.maxError) {
s := fmt.Sprintf("stddev %v != %v (allowed error %v, %v)", this.stddev, expected.stddev, expected.closeEnough, expected.maxError)
fmt.Println(s)
- return os.ErrorString(s)
+ return os.NewError(s)
}
return nil
}
diff --git a/src/pkg/reflect/type.go b/src/pkg/reflect/type.go
index aef6370db..6c1ab6098 100644
--- a/src/pkg/reflect/type.go
+++ b/src/pkg/reflect/type.go
@@ -827,7 +827,7 @@ func (t *commonType) runtimeType() *runtime.Type {
i runtime.Type
ct commonType
}
- return (*runtime.Type)(unsafe.Pointer(uintptr(unsafe.Pointer(t)) - uintptr(unsafe.Offsetof(rt.ct))))
+ return (*runtime.Type)(unsafe.Pointer(uintptr(unsafe.Pointer(t)) - unsafe.Offsetof(rt.ct)))
}
// PtrTo returns the pointer type with element t.
@@ -888,7 +888,7 @@ func PtrTo(t Type) Type {
p.uncommonType = nil
p.ptrToThis = nil
- p.elem = (*runtime.Type)(unsafe.Pointer(uintptr(unsafe.Pointer(ct)) - uintptr(unsafe.Offsetof(rt.ptrType))))
+ p.elem = (*runtime.Type)(unsafe.Pointer(uintptr(unsafe.Pointer(ct)) - unsafe.Offsetof(rt.ptrType)))
ptrMap.m[ct] = p
ptrMap.Unlock()
diff --git a/src/pkg/reflect/value.go b/src/pkg/reflect/value.go
index 3abe13e04..b1999aa63 100644
--- a/src/pkg/reflect/value.go
+++ b/src/pkg/reflect/value.go
@@ -11,7 +11,7 @@ import (
"unsafe"
)
-const ptrSize = uintptr(unsafe.Sizeof((*byte)(nil)))
+const ptrSize = unsafe.Sizeof((*byte)(nil))
const cannotSet = "cannot set value obtained from unexported struct field"
// TODO: This will have to go away when
diff --git a/src/pkg/regexp/regexp.go b/src/pkg/regexp/regexp.go
index e3221ac9d..44da8b671 100644
--- a/src/pkg/regexp/regexp.go
+++ b/src/pkg/regexp/regexp.go
@@ -87,16 +87,16 @@ func (e Error) String() string {
// Error codes returned by failures to parse an expression.
var (
- ErrInternal = Error("internal error")
- ErrUnmatchedLpar = Error("unmatched '('")
- ErrUnmatchedRpar = Error("unmatched ')'")
- ErrUnmatchedLbkt = Error("unmatched '['")
- ErrUnmatchedRbkt = Error("unmatched ']'")
- ErrBadRange = Error("bad range in character class")
- ErrExtraneousBackslash = Error("extraneous backslash")
- ErrBadClosure = Error("repeated closure (**, ++, etc.)")
- ErrBareClosure = Error("closure applies to nothing")
- ErrBadBackslash = Error("illegal backslash escape")
+ ErrInternal = Error("regexp: internal error")
+ ErrUnmatchedLpar = Error("regexp: unmatched '('")
+ ErrUnmatchedRpar = Error("regexp: unmatched ')'")
+ ErrUnmatchedLbkt = Error("regexp: unmatched '['")
+ ErrUnmatchedRbkt = Error("regexp: unmatched ']'")
+ ErrBadRange = Error("regexp: bad range in character class")
+ ErrExtraneousBackslash = Error("regexp: extraneous backslash")
+ ErrBadClosure = Error("regexp: repeated closure (**, ++, etc.)")
+ ErrBareClosure = Error("regexp: closure applies to nothing")
+ ErrBadBackslash = Error("regexp: illegal backslash escape")
)
const (
diff --git a/src/pkg/rpc/client.go b/src/pkg/rpc/client.go
index a8e560cbe..b1828614f 100644
--- a/src/pkg/rpc/client.go
+++ b/src/pkg/rpc/client.go
@@ -23,7 +23,7 @@ func (e ServerError) String() string {
return string(e)
}
-const ErrShutdown = os.ErrorString("connection is shut down")
+var ErrShutdown = os.NewError("connection is shut down")
// Call represents an active RPC.
type Call struct {
@@ -110,7 +110,7 @@ func (client *Client) input() {
if response.Error == "" {
err = client.codec.ReadResponseBody(c.Reply)
if err != nil {
- c.Error = os.ErrorString("reading body " + err.String())
+ c.Error = os.NewError("reading body " + err.String())
}
} else {
// We've got an error response. Give this to the request;
@@ -119,7 +119,7 @@ func (client *Client) input() {
c.Error = ServerError(response.Error)
err = client.codec.ReadResponseBody(nil)
if err != nil {
- err = os.ErrorString("reading error body: " + err.String())
+ err = os.NewError("reading error body: " + err.String())
}
}
c.done()
@@ -221,7 +221,7 @@ func DialHTTPPath(network, address, path string) (*Client, os.Error) {
return NewClient(conn), nil
}
if err == nil {
- err = os.ErrorString("unexpected HTTP response: " + resp.Status)
+ err = os.NewError("unexpected HTTP response: " + resp.Status)
}
conn.Close()
return nil, &net.OpError{"dial-http", network + " " + address, nil, err}
diff --git a/src/pkg/rpc/jsonrpc/all_test.go b/src/pkg/rpc/jsonrpc/all_test.go
index 764ee7ff3..02b9735eb 100644
--- a/src/pkg/rpc/jsonrpc/all_test.go
+++ b/src/pkg/rpc/jsonrpc/all_test.go
@@ -35,7 +35,7 @@ func (t *Arith) Mul(args *Args, reply *Reply) os.Error {
func (t *Arith) Div(args *Args, reply *Reply) os.Error {
if args.B == 0 {
- return os.ErrorString("divide by zero")
+ return os.NewError("divide by zero")
}
reply.C = args.A / args.B
return nil
diff --git a/src/pkg/rpc/server.go b/src/pkg/rpc/server.go
index acadeec37..17ba6a453 100644
--- a/src/pkg/rpc/server.go
+++ b/src/pkg/rpc/server.go
@@ -242,10 +242,10 @@ func (server *Server) register(rcvr interface{}, name string, useName bool) os.E
if s.typ.PkgPath() != "" && !isExported(sname) && !useName {
s := "rpc Register: type " + sname + " is not exported"
log.Print(s)
- return os.ErrorString(s)
+ return os.NewError(s)
}
if _, present := server.serviceMap[sname]; present {
- return os.ErrorString("rpc: service already defined: " + sname)
+ return os.NewError("rpc: service already defined: " + sname)
}
s.name = sname
s.method = make(map[string]*methodType)
@@ -294,7 +294,7 @@ func (server *Server) register(rcvr interface{}, name string, useName bool) os.E
if len(s.method) == 0 {
s := "rpc Register: type " + sname + " has no exported methods of suitable type"
log.Print(s)
- return os.ErrorString(s)
+ return os.NewError(s)
}
server.serviceMap[s.name] = s
return nil
@@ -491,13 +491,13 @@ func (server *Server) readRequest(codec ServerCodec) (req *Request, service *ser
if err == os.EOF || err == io.ErrUnexpectedEOF {
return
}
- err = os.ErrorString("rpc: server cannot decode request: " + err.String())
+ err = os.NewError("rpc: server cannot decode request: " + err.String())
return
}
serviceMethod := strings.Split(req.ServiceMethod, ".", -1)
if len(serviceMethod) != 2 {
- err = os.ErrorString("rpc: service/method request ill-formed: " + req.ServiceMethod)
+ err = os.NewError("rpc: service/method request ill-formed: " + req.ServiceMethod)
return
}
// Look up the request.
@@ -505,12 +505,12 @@ func (server *Server) readRequest(codec ServerCodec) (req *Request, service *ser
service = server.serviceMap[serviceMethod[0]]
server.Unlock()
if service == nil {
- err = os.ErrorString("rpc: can't find service " + req.ServiceMethod)
+ err = os.NewError("rpc: can't find service " + req.ServiceMethod)
return
}
mtype = service.method[serviceMethod[1]]
if mtype == nil {
- err = os.ErrorString("rpc: can't find method " + req.ServiceMethod)
+ err = os.NewError("rpc: can't find method " + req.ServiceMethod)
}
return
}
diff --git a/src/pkg/rpc/server_test.go b/src/pkg/rpc/server_test.go
index cfff0c9ad..1692168a8 100644
--- a/src/pkg/rpc/server_test.go
+++ b/src/pkg/rpc/server_test.go
@@ -52,7 +52,7 @@ func (t *Arith) Mul(args *Args, reply *Reply) os.Error {
func (t *Arith) Div(args Args, reply *Reply) os.Error {
if args.B == 0 {
- return os.ErrorString("divide by zero")
+ return os.NewError("divide by zero")
}
reply.C = args.A / args.B
return nil
diff --git a/src/pkg/runtime/Makefile b/src/pkg/runtime/Makefile
index b122e0599..79f847e64 100644
--- a/src/pkg/runtime/Makefile
+++ b/src/pkg/runtime/Makefile
@@ -12,9 +12,6 @@ SIZE_amd64=64
SIZE_arm=32
SIZE=$(SIZE_$(GOARCH))
-# TODO(kaib): fix register allocation to honor extern register so we
-# can enable optimizations again.
-CFLAGS_arm=-N
CFLAGS_windows=-D__WINDOWS__
CFLAGS=-I$(GOOS) -I$(GOARCH) -I$(GOOS)/$(GOARCH) -wF $(CFLAGS_$(GOARCH)) $(CFLAGS_$(GOOS))
diff --git a/src/pkg/runtime/cgo/Makefile b/src/pkg/runtime/cgo/Makefile
index f26da2c51..7e752f127 100644
--- a/src/pkg/runtime/cgo/Makefile
+++ b/src/pkg/runtime/cgo/Makefile
@@ -10,6 +10,10 @@ ifeq ($(GOARCH),arm)
ENABLED:=0
endif
+ifeq ($(GOOS),plan9)
+ENABLED:=0
+endif
+
ifeq ($(DISABLE_CGO),1)
ENABLED:=0
endif
diff --git a/src/pkg/runtime/cgo/darwin_386.c b/src/pkg/runtime/cgo/darwin_386.c
index 4fc7eb4e0..13184f321 100644
--- a/src/pkg/runtime/cgo/darwin_386.c
+++ b/src/pkg/runtime/cgo/darwin_386.c
@@ -8,11 +8,13 @@
static void* threadentry(void*);
static pthread_key_t k1, k2;
+#define magic1 (0x23581321U)
+
static void
inittls(void)
{
uint32 x, y;
- pthread_key_t tofree[16], k;
+ pthread_key_t tofree[128], k;
int i, ntofree;
int havek1, havek2;
@@ -35,9 +37,8 @@ inittls(void)
* 0x48+4*0x108 = 0x468 and 0x48+4*0x109 = 0x46c.
*
* The linker and runtime hard-code these constant offsets
- * from %gs where we expect to find m and g. The code
- * below verifies that the constants are correct once it has
- * obtained the keys. Known to ../cmd/8l/obj.c:/468
+ * from %gs where we expect to find m and g.
+ * Known to ../cmd/8l/obj.c:/468
* and to ../pkg/runtime/darwin/386/sys.s:/468
*
* This is truly disgusting and a bit fragile, but taking care
@@ -48,55 +49,54 @@ inittls(void)
* require an extra instruction and memory reference in
* every stack growth prolog and would also require
* rewriting the code that 8c generates for extern registers.
+ *
+ * Things get more disgusting on OS X 10.7 Lion.
+ * The 0x48 base mentioned above is the offset of the tsd
+ * array within the per-thread structure on Leopard and Snow Leopard.
+ * On Lion, the base moved a little, so while the math above
+ * still applies, the base is different. Thus, we cannot
+ * look for specific key values if we want to build binaries
+ * that run on both systems. Instead, forget about the
+ * specific key values and just allocate and initialize per-thread
+ * storage until we find a key that writes to the memory location
+ * we want. Then keep that key.
*/
havek1 = 0;
havek2 = 0;
ntofree = 0;
while(!havek1 || !havek2) {
if(pthread_key_create(&k, nil) < 0) {
- fprintf(stderr, "libcgo: pthread_key_create failed\n");
+ fprintf(stderr, "runtime/cgo: pthread_key_create failed\n");
abort();
}
- if(k == 0x108) {
+ pthread_setspecific(k, (void*)magic1);
+ asm volatile("movl %%gs:0x468, %0" : "=r"(x));
+ asm volatile("movl %%gs:0x46c, %0" : "=r"(y));
+ if(x == magic1) {
havek1 = 1;
k1 = k;
- continue;
- }
- if(k == 0x109) {
+ } else if(y == magic1) {
havek2 = 1;
k2 = k;
- continue;
+ } else {
+ if(ntofree >= nelem(tofree)) {
+ fprintf(stderr, "runtime/cgo: could not obtain pthread_keys\n");
+ fprintf(stderr, "\ttried");
+ for(i=0; i<ntofree; i++)
+ fprintf(stderr, " %#x", (unsigned)tofree[i]);
+ fprintf(stderr, "\n");
+ abort();
+ }
+ tofree[ntofree++] = k;
}
- if(ntofree >= nelem(tofree)) {
- fprintf(stderr, "libcgo: could not obtain pthread_keys\n");
- fprintf(stderr, "\twanted 0x108 and 0x109\n");
- fprintf(stderr, "\tgot");
- for(i=0; i<ntofree; i++)
- fprintf(stderr, " %#lx", tofree[i]);
- fprintf(stderr, "\n");
- abort();
- }
- tofree[ntofree++] = k;
+ pthread_setspecific(k, 0);
}
- for(i=0; i<ntofree; i++)
- pthread_key_delete(tofree[i]);
-
/*
- * We got the keys we wanted. Make sure that we observe
- * updates to k1 at 0x468, to verify that the TLS array
- * offset from %gs hasn't changed.
+ * We got the keys we wanted. Free the others.
*/
- pthread_setspecific(k1, (void*)0x12345678);
- asm volatile("movl %%gs:0x468, %0" : "=r"(x));
-
- pthread_setspecific(k1, (void*)0x87654321);
- asm volatile("movl %%gs:0x468, %0" : "=r"(y));
-
- if(x != 0x12345678 || y != 0x87654321) {
- printf("libcgo: thread-local storage %#lx not at %%gs:0x468 - x=%#x y=%#x\n", k1, x, y);
- abort();
- }
+ for(i=0; i<ntofree; i++)
+ pthread_key_delete(tofree[i]);
}
static void
diff --git a/src/pkg/runtime/cgo/darwin_amd64.c b/src/pkg/runtime/cgo/darwin_amd64.c
index 253a1b252..38cd80a6f 100644
--- a/src/pkg/runtime/cgo/darwin_amd64.c
+++ b/src/pkg/runtime/cgo/darwin_amd64.c
@@ -8,24 +8,25 @@
static void* threadentry(void*);
static pthread_key_t k1, k2;
+#define magic1 (0x23581321345589ULL)
+
static void
inittls(void)
{
uint64 x, y;
- pthread_key_t tofree[16], k;
+ pthread_key_t tofree[128], k;
int i, ntofree;
int havek1, havek2;
/*
* Same logic, code as darwin_386.c:/inittls, except that words
- * are 8 bytes long now, and the thread-local storage starts at 0x60.
- * So the offsets are
+ * are 8 bytes long now, and the thread-local storage starts
+ * at 0x60 on Leopard / Snow Leopard. So the offsets are
* 0x60+8*0x108 = 0x8a0 and 0x60+8*0x109 = 0x8a8.
*
* The linker and runtime hard-code these constant offsets
- * from %gs where we expect to find m and g. The code
- * below verifies that the constants are correct once it has
- * obtained the keys. Known to ../cmd/6l/obj.c:/8a0
+ * from %gs where we expect to find m and g.
+ * Known to ../cmd/6l/obj.c:/8a0
* and to ../pkg/runtime/darwin/amd64/sys.s:/8a0
*
* As disgusting as on the 386; same justification.
@@ -35,49 +36,37 @@ inittls(void)
ntofree = 0;
while(!havek1 || !havek2) {
if(pthread_key_create(&k, nil) < 0) {
- fprintf(stderr, "libcgo: pthread_key_create failed\n");
+ fprintf(stderr, "runtime/cgo: pthread_key_create failed\n");
abort();
}
- if(k == 0x108) {
+ pthread_setspecific(k, (void*)magic1);
+ asm volatile("movq %%gs:0x8a0, %0" : "=r"(x));
+ asm volatile("movq %%gs:0x8a8, %0" : "=r"(y));
+ if(x == magic1) {
havek1 = 1;
k1 = k;
- continue;
- }
- if(k == 0x109) {
+ } else if(y == magic1) {
havek2 = 1;
k2 = k;
- continue;
- }
- if(ntofree >= nelem(tofree)) {
- fprintf(stderr, "libcgo: could not obtain pthread_keys\n");
- fprintf(stderr, "\twanted 0x108 and 0x109\n");
- fprintf(stderr, "\tgot");
- for(i=0; i<ntofree; i++)
- fprintf(stderr, " %#x", (unsigned)tofree[i]);
- fprintf(stderr, "\n");
- abort();
+ } else {
+ if(ntofree >= nelem(tofree)) {
+ fprintf(stderr, "runtime/cgo: could not obtain pthread_keys\n");
+ fprintf(stderr, "\ttried");
+ for(i=0; i<ntofree; i++)
+ fprintf(stderr, " %#x", (unsigned)tofree[i]);
+ fprintf(stderr, "\n");
+ abort();
+ }
+ tofree[ntofree++] = k;
}
- tofree[ntofree++] = k;
+ pthread_setspecific(k, 0);
}
- for(i=0; i<ntofree; i++)
- pthread_key_delete(tofree[i]);
-
/*
- * We got the keys we wanted. Make sure that we observe
- * updates to k1 at 0x8a0, to verify that the TLS array
- * offset from %gs hasn't changed.
+ * We got the keys we wanted. Free the others.
*/
- pthread_setspecific(k1, (void*)0x123456789abcdef0ULL);
- asm volatile("movq %%gs:0x8a0, %0" : "=r"(x));
-
- pthread_setspecific(k2, (void*)0x0fedcba987654321);
- asm volatile("movq %%gs:0x8a8, %0" : "=r"(y));
-
- if(x != 0x123456789abcdef0ULL || y != 0x0fedcba987654321) {
- printf("libcgo: thread-local storage %#x not at %%gs:0x8a0 - x=%#llx y=%#llx\n", (unsigned)k1, x, y);
- abort();
- }
+ for(i=0; i<ntofree; i++)
+ pthread_key_delete(tofree[i]);
}
void
diff --git a/src/pkg/runtime/cgo/nacl_386.c b/src/pkg/runtime/cgo/nacl_386.c
deleted file mode 100644
index e556c433c..000000000
--- a/src/pkg/runtime/cgo/nacl_386.c
+++ /dev/null
@@ -1,19 +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.
-
-#include "libcgo.h"
-
-static void
-xinitcgo(void)
-{
-}
-
-void (*initcgo)(void) = xinitcgo;
-
-void
-libcgo_sys_thread_start(ThreadStart *ts)
-{
- // unimplemented
- *(int*)0 = 0;
-}
diff --git a/src/pkg/runtime/cgo/util.c b/src/pkg/runtime/cgo/util.c
index 0eff19aa6..9d96521f5 100644
--- a/src/pkg/runtime/cgo/util.c
+++ b/src/pkg/runtime/cgo/util.c
@@ -40,7 +40,7 @@ xlibcgo_thread_start(ThreadStart *arg)
/* Make our own copy that can persist after we return. */
ts = malloc(sizeof *ts);
if(ts == nil) {
- fprintf(stderr, "libcgo: out of memory in thread_start\n");
+ fprintf(stderr, "runtime/cgo: out of memory in thread_start\n");
abort();
}
*ts = *arg;
diff --git a/src/pkg/runtime/error.go b/src/pkg/runtime/error.go
index 289d78f49..6c37f888f 100644
--- a/src/pkg/runtime/error.go
+++ b/src/pkg/runtime/error.go
@@ -131,3 +131,8 @@ func printany(i interface{}) {
print("(", typestring(i), ") ", i)
}
}
+
+// called from generated code
+func panicwrap(pkg, typ, meth string) {
+ panic("value method " + pkg + "." + typ + "." + meth + " called using nil *" + typ + " pointer")
+}
diff --git a/src/pkg/runtime/linux/mem.c b/src/pkg/runtime/linux/mem.c
index 38ca7e4a0..ad0fac6d3 100644
--- a/src/pkg/runtime/linux/mem.c
+++ b/src/pkg/runtime/linux/mem.c
@@ -91,6 +91,9 @@ runtime·SysMap(void *v, uintptr n)
if(p != v && addrspace_free(v, n)) {
// On some systems, mmap ignores v without
// MAP_FIXED, so retry if the address space is free.
+ if(p > (void*)4096) {
+ runtime·munmap(p, n);
+ }
p = runtime·mmap(v, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
}
if(p == (void*)ENOMEM)
diff --git a/src/pkg/runtime/malloc.goc b/src/pkg/runtime/malloc.goc
index c55be9772..49ab24df8 100644
--- a/src/pkg/runtime/malloc.goc
+++ b/src/pkg/runtime/malloc.goc
@@ -229,7 +229,7 @@ runtime·allocmcache(void)
return c;
}
-int32 runtime·sizeof_C_MStats = sizeof(MStats);
+uintptr runtime·sizeof_C_MStats = sizeof(MStats);
#define MaxArena32 (2U<<30)
diff --git a/src/pkg/runtime/mem.go b/src/pkg/runtime/mem.go
index fe505a329..c3316d44c 100644
--- a/src/pkg/runtime/mem.go
+++ b/src/pkg/runtime/mem.go
@@ -52,7 +52,7 @@ type MemStatsType struct {
}
}
-var sizeof_C_MStats int // filled in by malloc.goc
+var sizeof_C_MStats uintptr // filled in by malloc.goc
func init() {
if sizeof_C_MStats != unsafe.Sizeof(MemStats) {
diff --git a/src/pkg/runtime/mkasmh.sh b/src/pkg/runtime/mkasmh.sh
index 91d1bbe5d..00b5b3c89 100755
--- a/src/pkg/runtime/mkasmh.sh
+++ b/src/pkg/runtime/mkasmh.sh
@@ -14,7 +14,6 @@ EOF
case "$GOARCH" in
386)
# The offsets 0 and 4 are also known to:
- # nacl/thread.c:/^newosproc
# ../../cmd/8l/pass.c:/D_GS
# ../../libcgo/linux_386.c:/^threadentry
# ../../libcgo/darwin_386.c:/^threadentry
diff --git a/src/pkg/runtime/plan9/386/sys.s b/src/pkg/runtime/plan9/386/sys.s
index f760b782f..1cb570b68 100644
--- a/src/pkg/runtime/plan9/386/sys.s
+++ b/src/pkg/runtime/plan9/386/sys.s
@@ -9,6 +9,11 @@
TEXT runtime·setldt(SB),7,$0
RET
+TEXT runtime·open(SB),7,$0
+ MOVL $14, AX
+ INT $64
+ RET
+
TEXT runtime·write(SB),7,$0
MOVL $20, AX
INT $64
diff --git a/src/pkg/runtime/plan9/os.h b/src/pkg/runtime/plan9/os.h
index 9444acc98..b2f7357ec 100644
--- a/src/pkg/runtime/plan9/os.h
+++ b/src/pkg/runtime/plan9/os.h
@@ -6,6 +6,14 @@ extern int32 runtime·write(int32 fd, void* buffer, int32 nbytes);
extern void runtime·exits(int8* msg);
extern int32 runtime·brk_(void*);
+/* open */
+enum
+{
+ OREAD = 0,
+ OWRITE = 1,
+ ORDWR = 2
+};
+
/* rfork */
enum
{
@@ -22,6 +30,28 @@ enum
RFREND = (1<<13),
RFNOMNT = (1<<14)
};
+
+typedef struct Tos Tos;
+typedef intptr Plink;
+
+struct Tos {
+ struct /* Per process profiling */
+ {
+ Plink *pp; /* known to be 0(ptr) */
+ Plink *next; /* known to be 4(ptr) */
+ Plink *last;
+ Plink *first;
+ uint32 pid;
+ uint32 what;
+ } prof;
+ uint64 cyclefreq; /* cycle clock frequency if there is one, 0 otherwise */
+ int64 kcycles; /* cycles spent in kernel */
+ int64 pcycles; /* cycles spent in process (kernel + user) */
+ uint32 pid; /* might as well put the pid here */
+ uint32 clock;
+ /* top of stack is here */
+};
+
extern int32 runtime·rfork(int32 flags, void *stk, M *m, G *g, void (*fn)(void));
extern int32 runtime·plan9_semacquire(uint32 *addr, int32 block);
extern int32 runtime·plan9_semrelease(uint32 *addr, int32 count);
diff --git a/src/pkg/runtime/plan9/thread.c b/src/pkg/runtime/plan9/thread.c
index 7c6ca45a3..ef9a23e8e 100644
--- a/src/pkg/runtime/plan9/thread.c
+++ b/src/pkg/runtime/plan9/thread.c
@@ -27,24 +27,48 @@ runtime·initsig(int32 queue)
{
}
+extern Tos *_tos;
void
runtime·exit(int32)
{
+ int32 fd;
+ uint8 buf[128];
+ uint8 tmp[16];
+ uint8 *p, *q;
+ int32 pid;
+
+ runtime·memclr(buf, sizeof buf);
+ runtime·memclr(tmp, sizeof tmp);
+ pid = _tos->pid;
+
+ /* build path string /proc/pid/notepg */
+ for(q=tmp; pid > 0;) {
+ *q++ = '0' + (pid%10);
+ pid = pid/10;
+ }
+ p = buf;
+ runtime·mcpy((void*)p, (void*)"/proc/", 6);
+ p += 6;
+ for(q--; q >= tmp;)
+ *p++ = *q--;
+ runtime·mcpy((void*)p, (void*)"/notepg", 7);
+
+ /* post interrupt note */
+ fd = runtime·open(buf, OWRITE);
+ runtime·write(fd, "interrupt", 9);
runtime·exits(nil);
}
void
runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
{
- USED(m, g, stk, fn);
-
m->tls[0] = m->id; // so 386 asm can find it
if(0){
runtime·printf("newosproc stk=%p m=%p g=%p fn=%p rfork=%p id=%d/%d ostk=%p\n",
stk, m, g, fn, runtime·rfork, m->id, m->tls[0], &m);
}
- if (runtime·rfork(RFPROC | RFMEM, stk, m, g, fn) < 0 )
+ if (runtime·rfork(RFPROC|RFMEM|RFNOWAIT, stk, m, g, fn) < 0 )
runtime·throw("newosproc: rfork failed");
}
diff --git a/src/pkg/runtime/pprof/pprof_test.go b/src/pkg/runtime/pprof/pprof_test.go
index a060917a2..4486d5525 100644
--- a/src/pkg/runtime/pprof/pprof_test.go
+++ b/src/pkg/runtime/pprof/pprof_test.go
@@ -43,7 +43,7 @@ func TestCPUProfile(t *testing.T) {
// Convert []byte to []uintptr.
bytes := prof.Bytes()
val := *(*[]uintptr)(unsafe.Pointer(&bytes))
- val = val[:len(bytes)/unsafe.Sizeof(uintptr(0))]
+ val = val[:len(bytes)/int(unsafe.Sizeof(uintptr(0)))]
if len(val) < 10 {
t.Fatalf("profile too short: %#x", val)
diff --git a/src/pkg/sort/search.go b/src/pkg/sort/search.go
index 6828e19b6..7d468da8a 100644
--- a/src/pkg/sort/search.go
+++ b/src/pkg/sort/search.go
@@ -15,7 +15,7 @@ package sort
// Search calls f(i) only for i in the range [0, n).
//
// A common use of Search is to find the index i for a value x in
-// a sorted, indexable data structure like an array or slice.
+// a sorted, indexable data structure such as an array or slice.
// In this case, the argument f, typically a closure, captures the value
// to be searched for, and how the data structure is indexed and
// ordered.
@@ -75,7 +75,7 @@ func Search(n int, f func(int) bool) int {
// Convenience wrappers for common cases.
// SearchInts searches for x in a sorted slice of ints and returns the index
-// as specified by Search. The array must be sorted in ascending order.
+// as specified by Search. The slice must be sorted in ascending order.
//
func SearchInts(a []int, x int) int {
return Search(len(a), func(i int) bool { return a[i] >= x })
@@ -83,15 +83,15 @@ func SearchInts(a []int, x int) int {
// SearchFloat64s searches for x in a sorted slice of float64s and returns the index
-// as specified by Search. The array must be sorted in ascending order.
+// as specified by Search. The slice must be sorted in ascending order.
//
func SearchFloat64s(a []float64, x float64) int {
return Search(len(a), func(i int) bool { return a[i] >= x })
}
-// SearchStrings searches for x in a sorted slice of strings and returns the index
-// as specified by Search. The array must be sorted in ascending order.
+// SearchStrings searches for x slice a sorted slice of strings and returns the index
+// as specified by Search. The slice must be sorted in ascending order.
//
func SearchStrings(a []string, x string) int {
return Search(len(a), func(i int) bool { return a[i] >= x })
@@ -99,12 +99,12 @@ func SearchStrings(a []string, x string) int {
// Search returns the result of applying SearchInts to the receiver and x.
-func (p IntArray) Search(x int) int { return SearchInts(p, x) }
+func (p IntSlice) Search(x int) int { return SearchInts(p, x) }
// Search returns the result of applying SearchFloat64s to the receiver and x.
-func (p Float64Array) Search(x float64) int { return SearchFloat64s(p, x) }
+func (p Float64Slice) Search(x float64) int { return SearchFloat64s(p, x) }
// Search returns the result of applying SearchStrings to the receiver and x.
-func (p StringArray) Search(x string) int { return SearchStrings(p, x) }
+func (p StringSlice) Search(x string) int { return SearchStrings(p, x) }
diff --git a/src/pkg/sort/search_test.go b/src/pkg/sort/search_test.go
index 939f66af3..2a9a85854 100644
--- a/src/pkg/sort/search_test.go
+++ b/src/pkg/sort/search_test.go
@@ -107,9 +107,9 @@ var wrappertests = []struct {
{"SearchInts", SearchInts(data, 11), 8},
{"SearchFloat64s", SearchFloat64s(fdata, 2.1), 4},
{"SearchStrings", SearchStrings(sdata, ""), 0},
- {"IntArray.Search", IntArray(data).Search(0), 2},
- {"Float64Array.Search", Float64Array(fdata).Search(2.0), 3},
- {"StringArray.Search", StringArray(sdata).Search("x"), 3},
+ {"IntSlice.Search", IntSlice(data).Search(0), 2},
+ {"Float64Slice.Search", Float64Slice(fdata).Search(2.0), 3},
+ {"StringSlice.Search", StringSlice(sdata).Search("x"), 3},
}
diff --git a/src/pkg/sort/sort.go b/src/pkg/sort/sort.go
index 30b1819af..b70757959 100644
--- a/src/pkg/sort/sort.go
+++ b/src/pkg/sort/sort.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package sort provides primitives for sorting arrays and user-defined
+// Package sort provides primitives for sorting slices and user-defined
// collections.
package sort
@@ -82,7 +82,7 @@ func doPivot(data Interface, lo, hi int) (midlo, midhi int) {
// data[d <= i < hi] = pivot
//
// Once b meets c, can swap the "= pivot" sections
- // into the middle of the array.
+ // into the middle of the slice.
pivot := lo
a, b, c, d := lo+1, lo+1, hi, hi
for b < c {
@@ -155,52 +155,52 @@ func IsSorted(data Interface) bool {
// Convenience types for common cases
-// IntArray attaches the methods of Interface to []int, sorting in increasing order.
-type IntArray []int
+// IntSlice attaches the methods of Interface to []int, sorting in increasing order.
+type IntSlice []int
-func (p IntArray) Len() int { return len(p) }
-func (p IntArray) Less(i, j int) bool { return p[i] < p[j] }
-func (p IntArray) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+func (p IntSlice) Len() int { return len(p) }
+func (p IntSlice) Less(i, j int) bool { return p[i] < p[j] }
+func (p IntSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
// Sort is a convenience method.
-func (p IntArray) Sort() { Sort(p) }
+func (p IntSlice) Sort() { Sort(p) }
-// Float64Array attaches the methods of Interface to []float64, sorting in increasing order.
-type Float64Array []float64
+// Float64Slice attaches the methods of Interface to []float64, sorting in increasing order.
+type Float64Slice []float64
-func (p Float64Array) Len() int { return len(p) }
-func (p Float64Array) Less(i, j int) bool { return p[i] < p[j] }
-func (p Float64Array) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+func (p Float64Slice) Len() int { return len(p) }
+func (p Float64Slice) Less(i, j int) bool { return p[i] < p[j] }
+func (p Float64Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
// Sort is a convenience method.
-func (p Float64Array) Sort() { Sort(p) }
+func (p Float64Slice) Sort() { Sort(p) }
-// StringArray attaches the methods of Interface to []string, sorting in increasing order.
-type StringArray []string
+// StringSlice attaches the methods of Interface to []string, sorting in increasing order.
+type StringSlice []string
-func (p StringArray) Len() int { return len(p) }
-func (p StringArray) Less(i, j int) bool { return p[i] < p[j] }
-func (p StringArray) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+func (p StringSlice) Len() int { return len(p) }
+func (p StringSlice) Less(i, j int) bool { return p[i] < p[j] }
+func (p StringSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
// Sort is a convenience method.
-func (p StringArray) Sort() { Sort(p) }
+func (p StringSlice) Sort() { Sort(p) }
// Convenience wrappers for common cases
-// SortInts sorts an array of ints in increasing order.
-func SortInts(a []int) { Sort(IntArray(a)) }
-// SortFloat64s sorts an array of float64s in increasing order.
-func SortFloat64s(a []float64) { Sort(Float64Array(a)) }
-// SortStrings sorts an array of strings in increasing order.
-func SortStrings(a []string) { Sort(StringArray(a)) }
+// SortInts sorts a slice of ints in increasing order.
+func SortInts(a []int) { Sort(IntSlice(a)) }
+// SortFloat64s sorts a slice of float64s in increasing order.
+func SortFloat64s(a []float64) { Sort(Float64Slice(a)) }
+// SortStrings sorts a slice of strings in increasing order.
+func SortStrings(a []string) { Sort(StringSlice(a)) }
-// IntsAreSorted tests whether an array of ints is sorted in increasing order.
-func IntsAreSorted(a []int) bool { return IsSorted(IntArray(a)) }
-// Float64sAreSorted tests whether an array of float64s is sorted in increasing order.
-func Float64sAreSorted(a []float64) bool { return IsSorted(Float64Array(a)) }
-// StringsAreSorted tests whether an array of strings is sorted in increasing order.
-func StringsAreSorted(a []string) bool { return IsSorted(StringArray(a)) }
+// IntsAreSorted tests whether a slice of ints is sorted in increasing order.
+func IntsAreSorted(a []int) bool { return IsSorted(IntSlice(a)) }
+// Float64sAreSorted tests whether a slice of float64s is sorted in increasing order.
+func Float64sAreSorted(a []float64) bool { return IsSorted(Float64Slice(a)) }
+// StringsAreSorted tests whether a slice of strings is sorted in increasing order.
+func StringsAreSorted(a []string) bool { return IsSorted(StringSlice(a)) }
diff --git a/src/pkg/sort/sort_test.go b/src/pkg/sort/sort_test.go
index 3d7337fd0..29359c83f 100644
--- a/src/pkg/sort/sort_test.go
+++ b/src/pkg/sort/sort_test.go
@@ -16,9 +16,9 @@ var ints = [...]int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984,
var float64s = [...]float64{74.3, 59.0, 238.2, -784.0, 2.3, 9845.768, -959.7485, 905, 7.8, 7.8}
var strings = [...]string{"", "Hello", "foo", "bar", "foo", "f00", "%*&^*&^&", "***"}
-func TestSortIntArray(t *testing.T) {
+func TestSortIntSlice(t *testing.T) {
data := ints
- a := IntArray(data[0:])
+ a := IntSlice(data[0:])
Sort(a)
if !IsSorted(a) {
t.Errorf("sorted %v", ints)
@@ -26,9 +26,9 @@ func TestSortIntArray(t *testing.T) {
}
}
-func TestSortFloat64Array(t *testing.T) {
+func TestSortFloat64Slice(t *testing.T) {
data := float64s
- a := Float64Array(data[0:])
+ a := Float64Slice(data[0:])
Sort(a)
if !IsSorted(a) {
t.Errorf("sorted %v", float64s)
@@ -36,9 +36,9 @@ func TestSortFloat64Array(t *testing.T) {
}
}
-func TestSortStringArray(t *testing.T) {
+func TestSortStringSlice(t *testing.T) {
data := strings
- a := StringArray(data[0:])
+ a := StringSlice(data[0:])
Sort(a)
if !IsSorted(a) {
t.Errorf("sorted %v", strings)
@@ -161,7 +161,7 @@ func (d *testingData) Len() int { return len(d.data) }
func (d *testingData) Less(i, j int) bool { return d.data[i] < d.data[j] }
func (d *testingData) Swap(i, j int) {
if d.nswap >= d.maxswap {
- d.t.Errorf("%s: used %d swaps sorting array of %d", d.desc, d.nswap, len(d.data))
+ d.t.Errorf("%s: used %d swaps sorting slice of %d", d.desc, d.nswap, len(d.data))
d.t.FailNow()
}
d.nswap++
@@ -255,13 +255,13 @@ func TestBentleyMcIlroy(t *testing.T) {
Sort(d)
// If we were testing C qsort, we'd have to make a copy
- // of the array and sort it ourselves and then compare
+ // of the slice and sort it ourselves and then compare
// x against it, to ensure that qsort was only permuting
// the data, not (for example) overwriting it with zeros.
//
// In go, we don't have to be so paranoid: since the only
// mutating method Sort can call is TestingData.swap,
- // it suffices here just to check that the final array is sorted.
+ // it suffices here just to check that the final slice is sorted.
if !IntsAreSorted(mdata) {
t.Errorf("%s: ints not sorted", desc)
t.Errorf("\t%v", mdata)
diff --git a/src/pkg/strconv/atoi.go b/src/pkg/strconv/atoi.go
index f7b845672..e1154782b 100644
--- a/src/pkg/strconv/atoi.go
+++ b/src/pkg/strconv/atoi.go
@@ -42,6 +42,8 @@ func cutoff64(base int) uint64 {
// digits, err.Error = os.EINVAL; if the value corresponding
// to s cannot be represented by a uint64, err.Error = os.ERANGE.
func Btoui64(s string, b int) (n uint64, err os.Error) {
+ var cutoff uint64
+
s0 := s
switch {
case len(s) < 1:
@@ -68,12 +70,12 @@ func Btoui64(s string, b int) (n uint64, err os.Error) {
}
default:
- err = os.ErrorString("invalid base " + Itoa(b))
+ err = os.NewError("invalid base " + Itoa(b))
goto Error
}
n = 0
- cutoff := cutoff64(b)
+ cutoff = cutoff64(b)
for i := 0; i < len(s); i++ {
var v byte
diff --git a/src/pkg/strconv/quote.go b/src/pkg/strconv/quote.go
index 98b19d3a2..05e49d32d 100644
--- a/src/pkg/strconv/quote.go
+++ b/src/pkg/strconv/quote.go
@@ -24,7 +24,10 @@ func quoteWith(s string, quote byte, ASCIIonly bool) string {
rune, width = utf8.DecodeRuneInString(s)
}
if width == 1 && rune == utf8.RuneError {
- goto printEscX
+ buf.WriteString(`\x`)
+ buf.WriteByte(lowerhex[s[0]>>4])
+ buf.WriteByte(lowerhex[s[0]&0xF])
+ continue
}
if rune == int(quote) || rune == '\\' { // always backslashed
buf.WriteByte('\\')
@@ -58,7 +61,6 @@ func quoteWith(s string, quote byte, ASCIIonly bool) string {
default:
switch {
case rune < ' ':
- printEscX:
buf.WriteString(`\x`)
buf.WriteByte(lowerhex[s[0]>>4])
buf.WriteByte(lowerhex[s[0]&0xF])
diff --git a/src/pkg/strings/reader.go b/src/pkg/strings/reader.go
index 10b0278e1..8423f7e45 100644
--- a/src/pkg/strings/reader.go
+++ b/src/pkg/strings/reader.go
@@ -49,7 +49,7 @@ func (r *Reader) ReadByte() (b byte, err os.Error) {
// read yet.
func (r *Reader) UnreadByte() os.Error {
if r.i <= 0 {
- return os.ErrorString("strings.Reader: at beginning of string")
+ return os.NewError("strings.Reader: at beginning of string")
}
r.i--
r.prevRune = -1
@@ -80,7 +80,7 @@ func (r *Reader) ReadRune() (rune int, size int, err os.Error) {
// The last method called on r must have been ReadRune.
func (r *Reader) UnreadRune() os.Error {
if r.prevRune < 0 {
- return os.ErrorString("strings.Reader: previous operation was not ReadRune")
+ return os.NewError("strings.Reader: previous operation was not ReadRune")
}
r.i = r.prevRune
r.prevRune = -1
diff --git a/src/pkg/sync/mutex_test.go b/src/pkg/sync/mutex_test.go
index f5c20ca49..9bfdec365 100644
--- a/src/pkg/sync/mutex_test.go
+++ b/src/pkg/sync/mutex_test.go
@@ -43,7 +43,7 @@ func BenchmarkContendedSemaphore(b *testing.B) {
s := new(uint32)
*s = 1
c := make(chan bool)
- runtime.GOMAXPROCS(2)
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
b.StartTimer()
go HammerSemaphore(s, b.N/2, c)
@@ -81,7 +81,7 @@ func BenchmarkContendedMutex(b *testing.B) {
b.StopTimer()
m := new(Mutex)
c := make(chan bool)
- runtime.GOMAXPROCS(2)
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
b.StartTimer()
go HammerMutex(m, b.N/2, c)
diff --git a/src/pkg/syscall/Makefile b/src/pkg/syscall/Makefile
index 9284fcc5d..d7bd58373 100644
--- a/src/pkg/syscall/Makefile
+++ b/src/pkg/syscall/Makefile
@@ -17,20 +17,26 @@ GOFILES=\
ztypes_$(GOOS)_$(GOARCH).go\
GOFILES_freebsd=\
+ bpf_bsd.go\
exec_unix.go\
route_bsd.go\
+ sockcmsg_unix.go\
syscall_bsd.go\
syscall_unix.go\
GOFILES_darwin=\
+ bpf_bsd.go\
exec_unix.go\
route_bsd.go\
+ sockcmsg_unix.go\
syscall_bsd.go\
syscall_unix.go\
GOFILES_linux=\
exec_unix.go\
+ lsf_linux.go\
netlink_linux.go\
+ sockcmsg_unix.go\
syscall_unix.go\
GOFILES_windows=\
diff --git a/src/pkg/syscall/bpf_bsd.go b/src/pkg/syscall/bpf_bsd.go
new file mode 100644
index 000000000..1eac9a3d8
--- /dev/null
+++ b/src/pkg/syscall/bpf_bsd.go
@@ -0,0 +1,167 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Berkeley packet filter for BSD variants
+
+package syscall
+
+import (
+ "unsafe"
+)
+
+func BpfStmt(code, k int) *BpfInsn {
+ return &BpfInsn{Code: uint16(code), K: uint32(k)}
+}
+
+func BpfJump(code, k, jt, jf int) *BpfInsn {
+ return &BpfInsn{Code: uint16(code), Jt: uint8(jt), Jf: uint8(jf), K: uint32(k)}
+}
+
+func BpfBuflen(fd int) (int, int) {
+ var l int
+ _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCGBLEN, uintptr(unsafe.Pointer(&l)))
+ if e := int(ep); e != 0 {
+ return 0, e
+ }
+ return l, 0
+}
+
+func SetBpfBuflen(fd, l int) (int, int) {
+ _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCSBLEN, uintptr(unsafe.Pointer(&l)))
+ if e := int(ep); e != 0 {
+ return 0, e
+ }
+ return l, 0
+}
+
+func BpfDatalink(fd int) (int, int) {
+ var t int
+ _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCGDLT, uintptr(unsafe.Pointer(&t)))
+ if e := int(ep); e != 0 {
+ return 0, e
+ }
+ return t, 0
+}
+
+func SetBpfDatalink(fd, t int) (int, int) {
+ _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCSDLT, uintptr(unsafe.Pointer(&t)))
+ if e := int(ep); e != 0 {
+ return 0, e
+ }
+ return t, 0
+}
+
+func SetBpfPromisc(fd, m int) int {
+ _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCPROMISC, uintptr(unsafe.Pointer(&m)))
+ if e := int(ep); e != 0 {
+ return e
+ }
+ return 0
+}
+
+func FlushBpf(fd int) int {
+ _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCFLUSH, 0)
+ if e := int(ep); e != 0 {
+ return e
+ }
+ return 0
+}
+
+type ivalue struct {
+ name [IFNAMSIZ]byte
+ value int16
+}
+
+func BpfInterface(fd int, name string) (string, int) {
+ var iv ivalue
+ _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCGETIF, uintptr(unsafe.Pointer(&iv)))
+ if e := int(ep); e != 0 {
+ return "", e
+ }
+ return name, 0
+}
+
+func SetBpfInterface(fd int, name string) int {
+ var iv ivalue
+ copy(iv.name[:], []byte(name))
+ _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCSETIF, uintptr(unsafe.Pointer(&iv)))
+ if e := int(ep); e != 0 {
+ return e
+ }
+ return 0
+}
+
+func BpfTimeout(fd int) (*Timeval, int) {
+ var tv Timeval
+ _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCGRTIMEOUT, uintptr(unsafe.Pointer(&tv)))
+ if e := int(ep); e != 0 {
+ return nil, e
+ }
+ return &tv, 0
+}
+
+func SetBpfTimeout(fd int, tv *Timeval) int {
+ _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCSRTIMEOUT, uintptr(unsafe.Pointer(tv)))
+ if e := int(ep); e != 0 {
+ return e
+ }
+ return 0
+}
+
+func BpfStats(fd int) (*BpfStat, int) {
+ var s BpfStat
+ _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCGSTATS, uintptr(unsafe.Pointer(&s)))
+ if e := int(ep); e != 0 {
+ return nil, e
+ }
+ return &s, 0
+}
+
+func SetBpfImmediate(fd, m int) int {
+ _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCIMMEDIATE, uintptr(unsafe.Pointer(&m)))
+ if e := int(ep); e != 0 {
+ return e
+ }
+ return 0
+}
+
+func SetBpf(fd int, i []BpfInsn) int {
+ var p BpfProgram
+ p.Len = uint32(len(i))
+ p.Insns = (*BpfInsn)(unsafe.Pointer(&i[0]))
+ _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCSETF, uintptr(unsafe.Pointer(&p)))
+ if e := int(ep); e != 0 {
+ return e
+ }
+ return 0
+}
+
+func CheckBpfVersion(fd int) int {
+ var v BpfVersion
+ _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCVERSION, uintptr(unsafe.Pointer(&v)))
+ if e := int(ep); e != 0 {
+ return e
+ }
+ if v.Major != BPF_MAJOR_VERSION || v.Minor != BPF_MINOR_VERSION {
+ return EINVAL
+ }
+ return 0
+}
+
+func BpfHeadercmpl(fd int) (int, int) {
+ var f int
+ _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCGHDRCMPLT, uintptr(unsafe.Pointer(&f)))
+ if e := int(ep); e != 0 {
+ return 0, e
+ }
+ return f, 0
+}
+
+func SetBpfHeadercmpl(fd, f int) int {
+ _, _, ep := Syscall(SYS_IOCTL, uintptr(fd), BIOCSHDRCMPLT, uintptr(unsafe.Pointer(&f)))
+ if e := int(ep); e != 0 {
+ return e
+ }
+ return 0
+}
diff --git a/src/pkg/syscall/exec_plan9.go b/src/pkg/syscall/exec_plan9.go
index 962b39b78..66ab1fced 100644
--- a/src/pkg/syscall/exec_plan9.go
+++ b/src/pkg/syscall/exec_plan9.go
@@ -62,7 +62,7 @@ var ForkLock sync.RWMutex
// Convert array of string to array
// of NUL-terminated byte pointer.
-func StringArrayPtr(ss []string) []*byte {
+func StringSlicePtr(ss []string) []*byte {
bb := make([]*byte, len(ss)+1)
for i := 0; i < len(ss); i++ {
bb[i] = StringBytePtr(ss[i])
@@ -169,7 +169,7 @@ func init() {
// no rescheduling, no malloc calls, and no new stack segments.
// The calls to RawSyscall are okay because they are assembly
// functions that do not grow the stack.
-func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, chroot, dir *byte, attr *ProcAttr, fdsToClose []int, pipe int) (pid int, err Error) {
+func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, dir *byte, attr *ProcAttr, fdsToClose []int, pipe int, rflag int) (pid int, err Error) {
// Declare all variables at top in case any
// declarations require heap allocation (e.g., errbuf).
var (
@@ -190,7 +190,7 @@ func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, chroot, dir *
// About to call fork.
// No more allocation or calls of non-assembly functions.
- r1, _, _ = RawSyscall(SYS_RFORK, uintptr(RFPROC|RFFDG|RFREND|clearenv), 0, 0)
+ r1, _, _ = RawSyscall(SYS_RFORK, uintptr(RFPROC|RFFDG|RFREND|clearenv|rflag), 0, 0)
if r1 != 0 {
if int(r1) == -1 {
@@ -338,14 +338,18 @@ type envItem struct {
}
type ProcAttr struct {
- Dir string // Current working directory.
- Env []string // Environment.
- Files []int // File descriptors.
- Chroot string // Chroot.
+ Dir string // Current working directory.
+ Env []string // Environment.
+ Files []int // File descriptors.
+ Sys *SysProcAttr
}
-var zeroAttributes ProcAttr
+type SysProcAttr struct {
+ Rfork int // additional flags to pass to rfork
+}
+var zeroProcAttr ProcAttr
+var zeroSysProcAttr SysProcAttr
func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err Error) {
var (
@@ -356,7 +360,11 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err Error)
)
if attr == nil {
- attr = &zeroAttributes
+ attr = &zeroProcAttr
+ }
+ sys := attr.Sys
+ if sys == nil {
+ sys = &zeroSysProcAttr
}
p[0] = -1
@@ -364,12 +372,8 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err Error)
// Convert args to C form.
argv0p := StringBytePtr(argv0)
- argvp := StringArrayPtr(argv)
+ argvp := StringSlicePtr(argv)
- var chroot *byte
- if attr.Chroot != "" {
- chroot = StringBytePtr(attr.Chroot)
- }
var dir *byte
if attr.Dir != "" {
dir = StringBytePtr(attr.Dir)
@@ -439,7 +443,7 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err Error)
fdsToClose = append(fdsToClose, p[0])
// Kick off child.
- pid, err = forkAndExecInChild(argv0p, argvp, envvParsed, chroot, dir, attr, fdsToClose, p[1])
+ pid, err = forkAndExecInChild(argv0p, argvp, envvParsed, dir, attr, fdsToClose, p[1], sys.Rfork)
if err != nil {
if p[0] >= 0 {
@@ -514,7 +518,7 @@ func Exec(argv0 string, argv []string, envv []string) (err Error) {
_, _, e := Syscall(SYS_EXEC,
uintptr(unsafe.Pointer(StringBytePtr(argv0))),
- uintptr(unsafe.Pointer(&StringArrayPtr(argv)[0])),
+ uintptr(unsafe.Pointer(&StringSlicePtr(argv)[0])),
0)
return NewError(e)
diff --git a/src/pkg/syscall/exec_unix.go b/src/pkg/syscall/exec_unix.go
index b6cb1baa2..4b3cfe47f 100644
--- a/src/pkg/syscall/exec_unix.go
+++ b/src/pkg/syscall/exec_unix.go
@@ -62,7 +62,7 @@ var ForkLock sync.RWMutex
// Convert array of string to array
// of NUL-terminated byte pointer.
-func StringArrayPtr(ss []string) []*byte {
+func StringSlicePtr(ss []string) []*byte {
bb := make([]*byte, len(ss)+1)
for i := 0; i < len(ss); i++ {
bb[i] = StringBytePtr(ss[i])
@@ -96,7 +96,7 @@ func SetNonblock(fd int, nonblocking bool) (errno int) {
// no rescheduling, no malloc calls, and no new stack segments.
// The calls to RawSyscall are okay because they are assembly
// functions that do not grow the stack.
-func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, pipe int) (pid int, err int) {
+func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err int) {
// Declare all variables at top in case any
// declarations require heap allocation (e.g., err1).
var r1, r2, err1 uintptr
@@ -131,7 +131,7 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
// Fork succeeded, now in child.
// Enable tracing if requested.
- if attr.Ptrace {
+ if sys.Ptrace {
_, _, err1 = RawSyscall(SYS_PTRACE, uintptr(PTRACE_TRACEME), 0, 0)
if err1 != 0 {
goto childerror
@@ -139,7 +139,7 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
}
// Session ID
- if attr.Setsid {
+ if sys.Setsid {
_, _, err1 = RawSyscall(SYS_SETSID, 0, 0, 0)
if err1 != 0 {
goto childerror
@@ -155,21 +155,21 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
}
// User and groups
- if attr.Credential != nil {
- ngroups := uintptr(len(attr.Credential.Groups))
+ if cred := sys.Credential; cred != nil {
+ ngroups := uintptr(len(cred.Groups))
groups := uintptr(0)
if ngroups > 0 {
- groups = uintptr(unsafe.Pointer(&attr.Credential.Groups[0]))
+ groups = uintptr(unsafe.Pointer(&cred.Groups[0]))
}
_, _, err1 = RawSyscall(SYS_SETGROUPS, ngroups, groups, 0)
if err1 != 0 {
goto childerror
}
- _, _, err1 = RawSyscall(SYS_SETGID, uintptr(attr.Credential.Gid), 0, 0)
+ _, _, err1 = RawSyscall(SYS_SETGID, uintptr(cred.Gid), 0, 0)
if err1 != 0 {
goto childerror
}
- _, _, err1 = RawSyscall(SYS_SETUID, uintptr(attr.Credential.Uid), 0, 0)
+ _, _, err1 = RawSyscall(SYS_SETUID, uintptr(cred.Uid), 0, 0)
if err1 != 0 {
goto childerror
}
@@ -249,7 +249,7 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
childerror:
// send error code on pipe
- RawSyscall(SYS_WRITE, uintptr(pipe), uintptr(unsafe.Pointer(&err1)), uintptr(unsafe.Sizeof(err1)))
+ RawSyscall(SYS_WRITE, uintptr(pipe), uintptr(unsafe.Pointer(&err1)), unsafe.Sizeof(err1))
for {
RawSyscall(SYS_EXIT, 253, 0, 0)
}
@@ -267,16 +267,21 @@ type Credential struct {
}
type ProcAttr struct {
- Setsid bool // Create session.
- Ptrace bool // Enable tracing.
- Dir string // Current working directory.
- Env []string // Environment.
- Files []int // File descriptors.
+ Dir string // Current working directory.
+ Env []string // Environment.
+ Files []int // File descriptors.
+ Sys *SysProcAttr
+}
+
+type SysProcAttr struct {
Chroot string // Chroot.
Credential *Credential // Credential.
+ Ptrace bool // Enable tracing.
+ Setsid bool // Create session.
}
-var zeroAttributes ProcAttr
+var zeroProcAttr ProcAttr
+var zeroSysProcAttr SysProcAttr
func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) {
var p [2]int
@@ -285,7 +290,11 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) {
var wstatus WaitStatus
if attr == nil {
- attr = &zeroAttributes
+ attr = &zeroProcAttr
+ }
+ sys := attr.Sys
+ if sys == nil {
+ sys = &zeroSysProcAttr
}
p[0] = -1
@@ -293,16 +302,16 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) {
// Convert args to C form.
argv0p := StringBytePtr(argv0)
- argvp := StringArrayPtr(argv)
- envvp := StringArrayPtr(attr.Env)
+ argvp := StringSlicePtr(argv)
+ envvp := StringSlicePtr(attr.Env)
if OS == "freebsd" && len(argv[0]) > len(argv0) {
argvp[0] = argv0p
}
var chroot *byte
- if attr.Chroot != "" {
- chroot = StringBytePtr(attr.Chroot)
+ if sys.Chroot != "" {
+ chroot = StringBytePtr(sys.Chroot)
}
var dir *byte
if attr.Dir != "" {
@@ -326,24 +335,18 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) {
}
// Kick off child.
- pid, err = forkAndExecInChild(argv0p, argvp, envvp, chroot, dir, attr, p[1])
+ pid, err = forkAndExecInChild(argv0p, argvp, envvp, chroot, dir, attr, sys, p[1])
if err != 0 {
- error:
- if p[0] >= 0 {
- Close(p[0])
- Close(p[1])
- }
- ForkLock.Unlock()
- return 0, err
+ goto error
}
ForkLock.Unlock()
// Read child error status from pipe.
Close(p[1])
- n, err = read(p[0], (*byte)(unsafe.Pointer(&err1)), unsafe.Sizeof(err1))
+ n, err = read(p[0], (*byte)(unsafe.Pointer(&err1)), int(unsafe.Sizeof(err1)))
Close(p[0])
if err != 0 || n != 0 {
- if n == unsafe.Sizeof(err1) {
+ if n == int(unsafe.Sizeof(err1)) {
err = int(err1)
}
if err == 0 {
@@ -361,6 +364,14 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) {
// Read got EOF, so pipe closed on exec, so exec succeeded.
return pid, 0
+
+error:
+ if p[0] >= 0 {
+ Close(p[0])
+ Close(p[1])
+ }
+ ForkLock.Unlock()
+ return 0, err
}
// Combination of fork and exec, careful to be thread safe.
@@ -378,7 +389,7 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid, handle int,
func Exec(argv0 string, argv []string, envv []string) (err int) {
_, _, err1 := RawSyscall(SYS_EXECVE,
uintptr(unsafe.Pointer(StringBytePtr(argv0))),
- uintptr(unsafe.Pointer(&StringArrayPtr(argv)[0])),
- uintptr(unsafe.Pointer(&StringArrayPtr(envv)[0])))
+ uintptr(unsafe.Pointer(&StringSlicePtr(argv)[0])),
+ uintptr(unsafe.Pointer(&StringSlicePtr(envv)[0])))
return int(err1)
}
diff --git a/src/pkg/syscall/exec_windows.go b/src/pkg/syscall/exec_windows.go
index b25f4a650..96a01e767 100644
--- a/src/pkg/syscall/exec_windows.go
+++ b/src/pkg/syscall/exec_windows.go
@@ -218,22 +218,32 @@ func joinExeDirAndFName(dir, p string) (name string, err int) {
}
type ProcAttr struct {
- Dir string
- Env []string
- Files []int
+ Dir string
+ Env []string
+ Files []int
+ Sys *SysProcAttr
+}
+
+type SysProcAttr struct {
HideWindow bool
CmdLine string // used if non-empty, else the windows command line is built by escaping the arguments passed to StartProcess
}
-var zeroAttributes ProcAttr
+var zeroProcAttr ProcAttr
+var zeroSysProcAttr SysProcAttr
func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid, handle int, err int) {
if len(argv0) == 0 {
return 0, 0, EWINDOWS
}
if attr == nil {
- attr = &zeroAttributes
+ attr = &zeroProcAttr
}
+ sys := attr.Sys
+ if sys == nil {
+ sys = &zeroSysProcAttr
+ }
+
if len(attr.Files) > 3 {
return 0, 0, EWINDOWS
}
@@ -257,8 +267,8 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid, handle int,
// Windows CreateProcess takes the command line as a single string:
// use attr.CmdLine if set, else build the command line by escaping
// and joining each argument with spaces
- if attr.CmdLine != "" {
- cmdline = attr.CmdLine
+ if sys.CmdLine != "" {
+ cmdline = sys.CmdLine
} else {
cmdline = makeCmdLine(argv)
}
@@ -293,7 +303,7 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid, handle int,
si := new(StartupInfo)
si.Cb = uint32(unsafe.Sizeof(*si))
si.Flags = STARTF_USESTDHANDLES
- if attr.HideWindow {
+ if sys.HideWindow {
si.Flags |= STARTF_USESHOWWINDOW
si.ShowWindow = SW_HIDE
}
diff --git a/src/pkg/syscall/lsf_linux.go b/src/pkg/syscall/lsf_linux.go
new file mode 100644
index 000000000..f2bd2b757
--- /dev/null
+++ b/src/pkg/syscall/lsf_linux.go
@@ -0,0 +1,78 @@
+// 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.
+
+// Linux socket filter
+
+package syscall
+
+import (
+ "unsafe"
+)
+
+func LsfStmt(code, k int) *SockFilter {
+ return &SockFilter{Code: uint16(code), K: uint32(k)}
+}
+
+func LsfJump(code, k, jt, jf int) *SockFilter {
+ return &SockFilter{Code: uint16(code), Jt: uint8(jt), Jf: uint8(jf), K: uint32(k)}
+}
+
+func LsfSocket(ifindex, proto int) (int, int) {
+ var lsall SockaddrLinklayer
+ s, e := Socket(AF_PACKET, SOCK_RAW, proto)
+ if e != 0 {
+ return 0, e
+ }
+ p := (*[2]byte)(unsafe.Pointer(&lsall.Protocol))
+ p[0] = byte(proto >> 8)
+ p[1] = byte(proto)
+ lsall.Ifindex = ifindex
+ e = Bind(s, &lsall)
+ if e != 0 {
+ Close(s)
+ return 0, e
+ }
+ return s, 0
+}
+
+type iflags struct {
+ name [IFNAMSIZ]byte
+ flags uint16
+}
+
+func SetLsfPromisc(name string, m bool) int {
+ s, e := Socket(AF_INET, SOCK_DGRAM, 0)
+ if e != 0 {
+ return e
+ }
+ defer Close(s)
+ var ifl iflags
+ copy(ifl.name[:], []byte(name))
+ _, _, ep := Syscall(SYS_IOCTL, uintptr(s), SIOCGIFFLAGS, uintptr(unsafe.Pointer(&ifl)))
+ if e := int(ep); e != 0 {
+ return e
+ }
+ if m {
+ ifl.flags |= uint16(IFF_PROMISC)
+ } else {
+ ifl.flags &= ^uint16(IFF_PROMISC)
+ }
+ _, _, ep = Syscall(SYS_IOCTL, uintptr(s), SIOCSIFFLAGS, uintptr(unsafe.Pointer(&ifl)))
+ if e := int(ep); e != 0 {
+ return e
+ }
+ return 0
+}
+
+func AttachLsf(fd int, i []SockFilter) int {
+ var p SockFprog
+ p.Len = uint16(len(i))
+ p.Filter = (*SockFilter)(unsafe.Pointer(&i[0]))
+ return setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, uintptr(unsafe.Pointer(&p)), unsafe.Sizeof(p))
+}
+
+func DetachLsf(fd int) int {
+ var dummy int
+ return setsockopt(fd, SOL_SOCKET, SO_DETACH_FILTER, uintptr(unsafe.Pointer(&dummy)), unsafe.Sizeof(dummy))
+}
diff --git a/src/pkg/syscall/mkall.sh b/src/pkg/syscall/mkall.sh
index 0a4ca0326..f031a38ed 100755
--- a/src/pkg/syscall/mkall.sh
+++ b/src/pkg/syscall/mkall.sh
@@ -120,14 +120,13 @@ freebsd_amd64)
darwin_386)
mkerrors="$mkerrors -f -m32"
mksyscall="./mksyscall.pl -l32"
- mksysnum="./mksysnum_darwin.pl /home/rsc/pub/xnu-1228/bsd/kern/syscalls.master"
+ mksysnum="./mksysnum_darwin.pl /usr/include/sys/syscall.h"
mktypes="godefs -gsyscall -f-m32"
;;
darwin_amd64)
mkerrors="$mkerrors -f -m64"
- mksysnum="./mksysnum_darwin.pl /home/rsc/pub/xnu-1228/bsd/kern/syscalls.master"
+ mksysnum="./mksysnum_darwin.pl /usr/include/sys/syscall.h"
mktypes="godefs -gsyscall -f-m64"
- mkerrors="./mkerrors.sh"
;;
linux_386)
mkerrors="$mkerrors -f -m32"
diff --git a/src/pkg/syscall/mkerrors.sh b/src/pkg/syscall/mkerrors.sh
index 1949ebfad..21583603f 100755
--- a/src/pkg/syscall/mkerrors.sh
+++ b/src/pkg/syscall/mkerrors.sh
@@ -30,7 +30,9 @@ includes_Linux='
#include <sys/stat.h>
#include <sys/types.h>
#include <linux/if_addr.h>
+#include <linux/if_ether.h>
#include <linux/if_tun.h>
+#include <linux/filter.h>
#include <linux/netlink.h>
#include <linux/reboot.h>
#include <linux/rtnetlink.h>
@@ -47,6 +49,7 @@ includes_Darwin='
#define _DARWIN_USE_64_BIT_INODE
#include <sys/types.h>
#include <sys/event.h>
+#include <sys/ptrace.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/sysctl.h>
@@ -59,6 +62,7 @@ includes_Darwin='
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_mroute.h>
+#include <termios.h>
'
includes_FreeBSD='
@@ -68,6 +72,7 @@ includes_FreeBSD='
#include <sys/sockio.h>
#include <sys/sysctl.h>
#include <sys/wait.h>
+#include <sys/ioctl.h>
#include <net/bpf.h>
#include <net/if.h>
#include <net/if_types.h>
@@ -136,12 +141,13 @@ done
$2 == "CTL_MAXNAME" ||
$2 ~ /^(MS|MNT)_/ ||
$2 ~ /^TUN(SET|GET|ATTACH|DETACH)/ ||
- $2 ~ /^(O|F|FD|NAME|S|PTRACE)_/ ||
+ $2 ~ /^(O|F|FD|NAME|S|PTRACE|PT)_/ ||
$2 ~ /^LINUX_REBOOT_CMD_/ ||
$2 ~ /^LINUX_REBOOT_MAGIC[12]$/ ||
$2 !~ "NLA_TYPE_MASK" &&
- $2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|RTM|RTN|RTPROT|RTA|RTAX|RTNH|ARPHRD)_/ ||
+ $2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|RTM|RTN|RTPROT|RTA|RTAX|RTNH|ARPHRD|ETH_P)_/ ||
$2 ~ /^SIOC/ ||
+ $2 ~ /^TIOC/ ||
$2 ~ /^(IFF|IFT|NET_RT|RTM|RTF|RTV|RTA|RTAX)_/ ||
$2 ~ /^BIOC/ ||
$2 !~ /^(BPF_TIMEVAL)$/ &&
diff --git a/src/pkg/syscall/mksyscall.pl b/src/pkg/syscall/mksyscall.pl
index ecf4abdd4..ed6525972 100755
--- a/src/pkg/syscall/mksyscall.pl
+++ b/src/pkg/syscall/mksyscall.pl
@@ -19,11 +19,12 @@
# block, as otherwise the system call could cause all goroutines to
# hang.
-$cmdline = "mksyscall.pl " . join(' ', @ARGV);
-$errors = 0;
-$_32bit = "";
-$nacl = 0;
-$plan9 = 0;
+use strict;
+
+my $cmdline = "mksyscall.pl " . join(' ', @ARGV);
+my $errors = 0;
+my $_32bit = "";
+my $plan9 = 0;
if($ARGV[0] eq "-b32") {
$_32bit = "big-endian";
@@ -32,10 +33,6 @@ if($ARGV[0] eq "-b32") {
$_32bit = "little-endian";
shift;
}
-if($ARGV[0] eq "-nacl") {
- $nacl = 1;
- shift;
-}
if($ARGV[0] eq "-plan9") {
$plan9 = 1;
shift;
@@ -66,7 +63,7 @@ sub parseparam($) {
return ($1, $2);
}
-$text = "";
+my $text = "";
while(<>) {
chomp;
s/\s+/ /g;
diff --git a/src/pkg/syscall/mksyscall_windows.pl b/src/pkg/syscall/mksyscall_windows.pl
index fb5a1272b..c3cb142ed 100755
--- a/src/pkg/syscall/mksyscall_windows.pl
+++ b/src/pkg/syscall/mksyscall_windows.pl
@@ -23,9 +23,13 @@
# //sys LoadLibrary(libname string) (handle uint32, errno int) [failretval==-1] = LoadLibraryA
# and is [failretval==0] by default.
-$cmdline = "mksyscall_windows.pl " . join(' ', @ARGV);
-$errors = 0;
-$_32bit = "";
+use strict;
+
+my $cmdline = "mksyscall_windows.pl " . join(' ', @ARGV);
+my $errors = 0;
+my $_32bit = "";
+
+binmode STDOUT;
if($ARGV[0] eq "-b32") {
$_32bit = "big-endian";
@@ -60,10 +64,10 @@ sub parseparam($) {
return ($1, $2);
}
-$text = "";
-$vars = "";
-$mods = "";
-$modnames = "";
+my $text = "";
+my $vars = "";
+my $mods = "";
+my $modnames = "";
while(<>) {
chomp;
s/\s+/ /g;
@@ -89,7 +93,7 @@ while(<>) {
if($modname eq "") {
$modname = "kernel32";
}
- $modvname = "mod$modname";
+ my $modvname = "mod$modname";
if($modnames !~ /$modname/) {
$modnames .= ".$modname";
$mods .= "\t$modvname = loadDll(\"$modname.dll\")\n";
@@ -101,7 +105,7 @@ while(<>) {
}
# System call pointer variable name.
- $sysvarname = "proc$sysname";
+ my $sysvarname = "proc$sysname";
# Returned value when failed
if($failcond eq "") {
@@ -109,17 +113,13 @@ while(<>) {
}
# Decide which version of api is used: ascii or unicode.
- if($sysname !~ /W$/) {
- $strconvfunc = "StringBytePtr";
- } else {
- $strconvfunc = "StringToUTF16Ptr";
- }
+ my $strconvfunc = $sysname !~ /W$/ ? "StringBytePtr" : "StringToUTF16Ptr";
# Winapi proc address variable.
$vars .= sprintf "\t%s = getSysProcAddr(%s, \"%s\")\n", $sysvarname, $modvname, $sysname;
# Go function header.
- my $out = join(', ', @out);
+ $out = join(', ', @out);
if($out ne "") {
$out = " ($out)";
}
@@ -240,7 +240,7 @@ while(<>) {
$failexpr = "$name $failcond";
}
}
- $failexpr =~ s/(=)([0-9A-Za-z\-+])/\1 \2/; # gofmt compatible
+ $failexpr =~ s/(=)([0-9A-Za-z\-+])/$1 $2/; # gofmt compatible
if($name eq "errno") {
# Set errno to "last error" only if returned value indicate failure
$body .= "\tif $failexpr {\n";
diff --git a/src/pkg/syscall/mksysnum_darwin.pl b/src/pkg/syscall/mksysnum_darwin.pl
index d078a1836..fd4375b2f 100755
--- a/src/pkg/syscall/mksysnum_darwin.pl
+++ b/src/pkg/syscall/mksysnum_darwin.pl
@@ -3,8 +3,9 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
#
-# Generate system call table for Darwin from master list
-# (for example, xnu-1228/bsd/kern/syscalls.master).
+# Generate system call table for Darwin from sys/syscall.h
+
+use strict;
my $command = "mksysnum_darwin.pl " . join(' ', @ARGV);
@@ -18,18 +19,11 @@ const (
EOF
while(<>){
- if(/^([0-9]+)\s+ALL\s+({ \S+\s+(\w+).*})/){
- my $num = $1;
- my $proto = $2;
- my $name = "SYS_$3";
+ if(/^#define\s+SYS_(\w+)\s+([0-9]+)/){
+ my $name = $1;
+ my $num = $2;
$name =~ y/a-z/A-Z/;
-
- # There are multiple entries for enosys and nosys, so comment them out.
- if($name =~ /^SYS_E?NOSYS$/){
- $name = "// $name";
- }
-
- print " $name = $num; // $proto\n";
+ print " SYS_$name = $num;"
}
}
diff --git a/src/pkg/syscall/mksysnum_freebsd.pl b/src/pkg/syscall/mksysnum_freebsd.pl
index 03f7d9e25..54872b2f4 100755
--- a/src/pkg/syscall/mksysnum_freebsd.pl
+++ b/src/pkg/syscall/mksysnum_freebsd.pl
@@ -6,6 +6,8 @@
# Generate system call table for FreeBSD from master list
# (for example, /usr/src/sys/kern/syscalls.master).
+use strict;
+
my $command = "mksysnum_freebsd.pl " . join(' ', @ARGV);
print <<EOF;
diff --git a/src/pkg/syscall/mksysnum_linux.pl b/src/pkg/syscall/mksysnum_linux.pl
index e97c87f44..ecf364188 100755
--- a/src/pkg/syscall/mksysnum_linux.pl
+++ b/src/pkg/syscall/mksysnum_linux.pl
@@ -3,6 +3,8 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
+use strict;
+
my $command = "mksysnum_linux.pl ". join(' ', @ARGV);
print <<EOF;
diff --git a/src/pkg/syscall/route_bsd.go b/src/pkg/syscall/route_bsd.go
index 79a8793d5..7821a6d29 100644
--- a/src/pkg/syscall/route_bsd.go
+++ b/src/pkg/syscall/route_bsd.go
@@ -10,8 +10,6 @@ import (
"unsafe"
)
-const darwinAMD64 = OS == "darwin" && ARCH == "amd64"
-
// Round the length of a raw sockaddr up to align it properly.
func rsaAlignOf(salen int) int {
salign := sizeofPtr
@@ -59,7 +57,7 @@ type RoutingMessage interface {
sockaddr() []Sockaddr
}
-const anyMessageLen = unsafe.Sizeof(anyMessage{})
+const anyMessageLen = int(unsafe.Sizeof(anyMessage{}))
type anyMessage struct {
Msglen uint16
diff --git a/src/pkg/syscall/sockcmsg_unix.go b/src/pkg/syscall/sockcmsg_unix.go
new file mode 100644
index 000000000..f0c05eaf3
--- /dev/null
+++ b/src/pkg/syscall/sockcmsg_unix.go
@@ -0,0 +1,65 @@
+// 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.
+
+// Socket control messages
+
+package syscall
+
+import (
+ "unsafe"
+)
+
+// Round the length of a raw sockaddr up to align it propery.
+func cmsgAlignOf(salen int) int {
+ salign := sizeofPtr
+ // NOTE: It seems like 64-bit Darwin kernel still requires 32-bit
+ // aligned access to BSD subsystem.
+ if darwinAMD64 {
+ salign = 4
+ }
+ if salen == 0 {
+ return salign
+ }
+ return (salen + salign - 1) & ^(salign - 1)
+}
+
+func cmsgLen(datalen int) int {
+ return cmsgAlignOf(SizeofCmsghdr) + datalen
+}
+
+type SocketControlMessage struct {
+ Header Cmsghdr
+ Data []byte
+}
+
+func ParseSocketControlMessage(buf []byte) ([]SocketControlMessage, int) {
+ var (
+ h *Cmsghdr
+ dbuf []byte
+ e int
+ cmsgs []SocketControlMessage
+ )
+
+ for len(buf) >= cmsgLen(0) {
+ h, dbuf, e = socketControlMessageHeaderAndData(buf)
+ if e != 0 {
+ break
+ }
+ m := SocketControlMessage{}
+ m.Header = *h
+ m.Data = dbuf[:int(h.Len)-cmsgAlignOf(SizeofCmsghdr)]
+ cmsgs = append(cmsgs, m)
+ buf = buf[cmsgAlignOf(int(h.Len)):]
+ }
+
+ return cmsgs, e
+}
+
+func socketControlMessageHeaderAndData(buf []byte) (*Cmsghdr, []byte, int) {
+ h := (*Cmsghdr)(unsafe.Pointer(&buf[0]))
+ if h.Len < SizeofCmsghdr || int(h.Len) > len(buf) {
+ return nil, nil, EINVAL
+ }
+ return h, buf[cmsgAlignOf(SizeofCmsghdr):], 0
+}
diff --git a/src/pkg/syscall/syscall.go b/src/pkg/syscall/syscall.go
index 157abaa8b..9f777f59e 100644
--- a/src/pkg/syscall/syscall.go
+++ b/src/pkg/syscall/syscall.go
@@ -13,11 +13,6 @@
// errno is an operating system error number describing the failure.
package syscall
-import (
- "sync"
- "unsafe"
-)
-
// StringByteSlice returns a NUL-terminated slice of bytes
// containing the text of s.
func StringByteSlice(s string) []byte {
@@ -33,63 +28,3 @@ func StringBytePtr(s string) *byte { return &StringByteSlice(s)[0] }
// Single-word zero for use when we need a valid pointer to 0 bytes.
// See mksyscall.sh.
var _zero uintptr
-
-// Mmap manager, for use by operating system-specific implementations.
-
-type mmapper struct {
- sync.Mutex
- active map[*byte][]byte // active mappings; key is last byte in mapping
- mmap func(addr, length uintptr, prot, flags, fd int, offset int64) (uintptr, int)
- munmap func(addr uintptr, length uintptr) int
-}
-
-func (m *mmapper) Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, errno int) {
- if length <= 0 {
- return nil, EINVAL
- }
-
- // Map the requested memory.
- addr, errno := m.mmap(0, uintptr(length), prot, flags, fd, offset)
- if errno != 0 {
- return nil, errno
- }
-
- // Slice memory layout
- var sl = struct {
- addr uintptr
- len int
- cap int
- }{addr, length, length}
-
- // Use unsafe to turn sl into a []byte.
- b := *(*[]byte)(unsafe.Pointer(&sl))
-
- // Register mapping in m and return it.
- p := &b[cap(b)-1]
- m.Lock()
- defer m.Unlock()
- m.active[p] = b
- return b, 0
-}
-
-func (m *mmapper) Munmap(data []byte) (errno int) {
- if len(data) == 0 || len(data) != cap(data) {
- return EINVAL
- }
-
- // Find the base of the mapping.
- p := &data[cap(data)-1]
- m.Lock()
- defer m.Unlock()
- b := m.active[p]
- if b == nil || &b[0] != &data[0] {
- return EINVAL
- }
-
- // Unmap the memory and update m.
- if errno := m.munmap(uintptr(unsafe.Pointer(&b[0])), uintptr(len(b))); errno != 0 {
- return errno
- }
- m.active[p] = nil, false
- return 0
-}
diff --git a/src/pkg/syscall/syscall_bsd.go b/src/pkg/syscall/syscall_bsd.go
index 89bcc7f0e..2df75917b 100644
--- a/src/pkg/syscall/syscall_bsd.go
+++ b/src/pkg/syscall/syscall_bsd.go
@@ -155,7 +155,7 @@ func Sleep(ns int64) (errno int) {
//sys connect(s int, addr uintptr, addrlen _Socklen) (errno int)
//sysnb socket(domain int, typ int, proto int) (fd int, errno int)
//sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (errno int)
-//sys setsockopt(s int, level int, name int, val uintptr, vallen int) (errno int)
+//sys setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (errno int)
//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int)
//sysnb getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int)
//sys Shutdown(s int, how int) (errno int)
@@ -400,7 +400,7 @@ func SetsockoptIPv6Mreq(fd, level, opt int, mreq *IPv6Mreq) (errno int) {
}
func SetsockoptString(fd, level, opt int, s string) (errno int) {
- return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(&[]byte(s)[0])), len(s))
+ return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(&[]byte(s)[0])), uintptr(len(s)))
}
//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, errno int)
@@ -425,6 +425,80 @@ func Sendto(fd int, p []byte, flags int, to Sockaddr) (errno int) {
return sendto(fd, p, flags, ptr, n)
}
+//sys recvmsg(s int, msg *Msghdr, flags int) (n int, errno int)
+
+func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, errno int) {
+ var msg Msghdr
+ var rsa RawSockaddrAny
+ msg.Name = (*byte)(unsafe.Pointer(&rsa))
+ msg.Namelen = uint32(SizeofSockaddrAny)
+ var iov Iovec
+ if len(p) > 0 {
+ iov.Base = (*byte)(unsafe.Pointer(&p[0]))
+ iov.SetLen(len(p))
+ }
+ var dummy byte
+ if len(oob) > 0 {
+ // receive at least one normal byte
+ if len(p) == 0 {
+ iov.Base = &dummy
+ iov.SetLen(1)
+ }
+ msg.Control = (*byte)(unsafe.Pointer(&oob[0]))
+ msg.SetControllen(len(oob))
+ }
+ msg.Iov = &iov
+ msg.Iovlen = 1
+ if n, errno = recvmsg(fd, &msg, flags); errno != 0 {
+ return
+ }
+ oobn = int(msg.Controllen)
+ recvflags = int(msg.Flags)
+ // source address is only specified if the socket is unconnected
+ if rsa.Addr.Family != AF_UNSPEC {
+ from, errno = anyToSockaddr(&rsa)
+ }
+ return
+}
+
+//sys sendmsg(s int, msg *Msghdr, flags int) (errno int)
+
+func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (errno int) {
+ var ptr uintptr
+ var salen _Socklen
+ if to != nil {
+ var err int
+ ptr, salen, err = to.sockaddr()
+ if err != 0 {
+ return err
+ }
+ }
+ var msg Msghdr
+ msg.Name = (*byte)(unsafe.Pointer(ptr))
+ msg.Namelen = uint32(salen)
+ var iov Iovec
+ if len(p) > 0 {
+ iov.Base = (*byte)(unsafe.Pointer(&p[0]))
+ iov.SetLen(len(p))
+ }
+ var dummy byte
+ if len(oob) > 0 {
+ // send at least one normal byte
+ if len(p) == 0 {
+ iov.Base = &dummy
+ iov.SetLen(1)
+ }
+ msg.Control = (*byte)(unsafe.Pointer(&oob[0]))
+ msg.SetControllen(len(oob))
+ }
+ msg.Iov = &iov
+ msg.Iovlen = 1
+ if errno = sendmsg(fd, &msg, flags); errno != 0 {
+ return
+ }
+ return
+}
+
// TODO:
// FreeBSD has IP_SENDIF. Darwin probably needs BSDLLCTest, see:
// http://developer.apple.com/mac/library/samplecode/BSDLLCTest/index.html
@@ -451,7 +525,7 @@ func Kevent(kq int, changes, events []Kevent_t, timeout *Timespec) (n int, errno
// Translate "kern.hostname" to []_C_int{0,1,2,3}.
func nametomib(name string) (mib []_C_int, errno int) {
- const siz = uintptr(unsafe.Sizeof(mib[0]))
+ const siz = unsafe.Sizeof(mib[0])
// NOTE(rsc): It seems strange to set the buffer to have
// size CTL_MAXNAME+2 but use only CTL_MAXNAME
@@ -540,14 +614,6 @@ func Futimes(fd int, tv []Timeval) (errno int) {
//sys fcntl(fd int, cmd int, arg int) (val int, errno int)
-func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, errno int) {
- return 0, 0, 0, nil, EAFNOSUPPORT
-}
-
-func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (errno int) {
- return EAFNOSUPPORT
-}
-
// TODO: wrap
// Acct(name nil-string) (errno int)
// Gethostuuid(uuid *byte, timeout *Timespec) (errno int)
diff --git a/src/pkg/syscall/syscall_darwin.go b/src/pkg/syscall/syscall_darwin.go
index 9e153b73d..fabd48178 100644
--- a/src/pkg/syscall/syscall_darwin.go
+++ b/src/pkg/syscall/syscall_darwin.go
@@ -56,6 +56,10 @@ func ParseDirent(buf []byte, max int, names []string) (consumed int, count int,
return origlen - len(buf), count, names
}
+//sys ptrace(request int, pid int, addr uintptr, data uintptr) (errno int)
+func PtraceAttach(pid int) (errno int) { return ptrace(PT_ATTACH, pid, 0, 0) }
+func PtraceDetach(pid int) (errno int) { return ptrace(PT_DETACH, pid, 0, 0) }
+
// TODO
func Sendfile(outfd int, infd int, offset *int64, count int) (written int, errno int) {
return -1, ENOSYS
diff --git a/src/pkg/syscall/syscall_darwin_386.go b/src/pkg/syscall/syscall_darwin_386.go
index 5101ba6c7..d76b22844 100644
--- a/src/pkg/syscall/syscall_darwin_386.go
+++ b/src/pkg/syscall/syscall_darwin_386.go
@@ -40,4 +40,16 @@ func SetKevent(k *Kevent_t, fd, mode, flags int) {
k.Flags = uint16(flags)
}
+func (iov *Iovec) SetLen(length int) {
+ iov.Len = uint32(length)
+}
+
+func (msghdr *Msghdr) SetControllen(length int) {
+ msghdr.Controllen = uint32(length)
+}
+
+func (cmsg *Cmsghdr) SetLen(length int) {
+ cmsg.Len = uint32(length)
+}
+
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr) // sic
diff --git a/src/pkg/syscall/syscall_darwin_amd64.go b/src/pkg/syscall/syscall_darwin_amd64.go
index acf7a5554..ed4372304 100644
--- a/src/pkg/syscall/syscall_darwin_amd64.go
+++ b/src/pkg/syscall/syscall_darwin_amd64.go
@@ -39,3 +39,15 @@ func SetKevent(k *Kevent_t, fd, mode, flags int) {
k.Filter = int16(mode)
k.Flags = uint16(flags)
}
+
+func (iov *Iovec) SetLen(length int) {
+ iov.Len = uint64(length)
+}
+
+func (msghdr *Msghdr) SetControllen(length int) {
+ msghdr.Controllen = uint32(length)
+}
+
+func (cmsg *Cmsghdr) SetLen(length int) {
+ cmsg.Len = uint32(length)
+}
diff --git a/src/pkg/syscall/syscall_freebsd_386.go b/src/pkg/syscall/syscall_freebsd_386.go
index d0fa506c7..d3b5a1bfe 100644
--- a/src/pkg/syscall/syscall_freebsd_386.go
+++ b/src/pkg/syscall/syscall_freebsd_386.go
@@ -29,4 +29,16 @@ func SetKevent(k *Kevent_t, fd, mode, flags int) {
k.Flags = uint16(flags)
}
+func (iov *Iovec) SetLen(length int) {
+ iov.Len = uint32(length)
+}
+
+func (msghdr *Msghdr) SetControllen(length int) {
+ msghdr.Controllen = uint32(length)
+}
+
+func (cmsg *Cmsghdr) SetLen(length int) {
+ cmsg.Len = uint32(length)
+}
+
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr) // sic
diff --git a/src/pkg/syscall/syscall_freebsd_amd64.go b/src/pkg/syscall/syscall_freebsd_amd64.go
index ef5aff6ef..8c1ddf6db 100644
--- a/src/pkg/syscall/syscall_freebsd_amd64.go
+++ b/src/pkg/syscall/syscall_freebsd_amd64.go
@@ -28,3 +28,15 @@ func SetKevent(k *Kevent_t, fd, mode, flags int) {
k.Filter = int16(mode)
k.Flags = uint16(flags)
}
+
+func (iov *Iovec) SetLen(length int) {
+ iov.Len = uint64(length)
+}
+
+func (msghdr *Msghdr) SetControllen(length int) {
+ msghdr.Controllen = uint32(length)
+}
+
+func (cmsg *Cmsghdr) SetLen(length int) {
+ cmsg.Len = uint32(length)
+}
diff --git a/src/pkg/syscall/syscall_linux.go b/src/pkg/syscall/syscall_linux.go
index 63682d23c..1d6fc76c7 100644
--- a/src/pkg/syscall/syscall_linux.go
+++ b/src/pkg/syscall/syscall_linux.go
@@ -472,7 +472,7 @@ func SetsockoptIPv6Mreq(fd, level, opt int, mreq *IPv6Mreq) (errno int) {
}
func SetsockoptString(fd, level, opt int, s string) (errno int) {
- return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(&[]byte(s)[0])), len(s))
+ return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(&[]byte(s)[0])), uintptr(len(s)))
}
func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, errno int) {
@@ -529,17 +529,17 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from
func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (errno int) {
var ptr uintptr
- var nsock _Socklen
+ var salen _Socklen
if to != nil {
var err int
- ptr, nsock, err = to.sockaddr()
+ ptr, salen, err = to.sockaddr()
if err != 0 {
return err
}
}
var msg Msghdr
msg.Name = (*byte)(unsafe.Pointer(ptr))
- msg.Namelen = uint32(nsock)
+ msg.Namelen = uint32(salen)
var iov Iovec
if len(p) > 0 {
iov.Base = (*byte)(unsafe.Pointer(&p[0]))
diff --git a/src/pkg/syscall/syscall_linux_386.go b/src/pkg/syscall/syscall_linux_386.go
index 5195179a2..44891de87 100644
--- a/src/pkg/syscall/syscall_linux_386.go
+++ b/src/pkg/syscall/syscall_linux_386.go
@@ -146,8 +146,8 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (errn
return
}
-func setsockopt(s int, level int, name int, val uintptr, vallen int) (errno int) {
- _, errno = socketcall(_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
+func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (errno int) {
+ _, errno = socketcall(_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), val, vallen, 0)
return
}
@@ -190,13 +190,13 @@ func Shutdown(s, how int) (errno int) {
}
func Fstatfs(fd int, buf *Statfs_t) (errno int) {
- _, _, e1 := Syscall(SYS_FSTATFS64, uintptr(fd), uintptr(unsafe.Sizeof(*buf)), uintptr(unsafe.Pointer(buf)))
+ _, _, e1 := Syscall(SYS_FSTATFS64, uintptr(fd), unsafe.Sizeof(*buf), uintptr(unsafe.Pointer(buf)))
errno = int(e1)
return
}
func Statfs(path string, buf *Statfs_t) (errno int) {
- _, _, e1 := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Sizeof(*buf)), uintptr(unsafe.Pointer(buf)))
+ _, _, e1 := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(StringBytePtr(path))), unsafe.Sizeof(*buf), uintptr(unsafe.Pointer(buf)))
errno = int(e1)
return
}
diff --git a/src/pkg/syscall/syscall_linux_amd64.go b/src/pkg/syscall/syscall_linux_amd64.go
index db9524668..8b206ad0a 100644
--- a/src/pkg/syscall/syscall_linux_amd64.go
+++ b/src/pkg/syscall/syscall_linux_amd64.go
@@ -42,7 +42,7 @@ package syscall
//sysnb getgroups(n int, list *_Gid_t) (nn int, errno int)
//sysnb setgroups(n int, list *_Gid_t) (errno int)
//sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (errno int)
-//sys setsockopt(s int, level int, name int, val uintptr, vallen int) (errno int)
+//sys setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (errno int)
//sysnb socket(domain int, typ int, proto int) (fd int, errno int)
//sysnb socketpair(domain int, typ int, proto int, fd *[2]int) (errno int)
//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int)
diff --git a/src/pkg/syscall/syscall_linux_arm.go b/src/pkg/syscall/syscall_linux_arm.go
index 37845301f..8c03c765c 100644
--- a/src/pkg/syscall/syscall_linux_arm.go
+++ b/src/pkg/syscall/syscall_linux_arm.go
@@ -71,7 +71,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, errno int)
//sysnb getgroups(n int, list *_Gid_t) (nn int, errno int) = SYS_GETGROUPS32
//sysnb setgroups(n int, list *_Gid_t) (errno int) = SYS_SETGROUPS32
//sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (errno int)
-//sys setsockopt(s int, level int, name int, val uintptr, vallen int) (errno int)
+//sys setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (errno int)
//sysnb socket(domain int, typ int, proto int) (fd int, errno int)
//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int)
//sysnb getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int)
diff --git a/src/pkg/syscall/syscall_plan9.go b/src/pkg/syscall/syscall_plan9.go
index 730126f23..4104050fd 100644
--- a/src/pkg/syscall/syscall_plan9.go
+++ b/src/pkg/syscall/syscall_plan9.go
@@ -35,7 +35,7 @@ var (
Stdout = 1
Stderr = 2
- EISDIR Error = NewError("file is a directory")
+ EISDIR = NewError("file is a directory")
)
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err string)
@@ -200,6 +200,17 @@ type Waitmsg struct {
Msg string
}
+func (w Waitmsg) Exited() bool { return true }
+func (w Waitmsg) Signaled() bool { return false }
+
+func (w Waitmsg) ExitStatus() int {
+ if len(w.Msg) == 0 {
+ // a normal exit returns no message
+ return 0
+ }
+ return 1
+}
+
//sys await(s []byte) (n int, err Error)
func Await(w *Waitmsg) (err Error) {
var buf [512]byte
@@ -230,7 +241,7 @@ func Await(w *Waitmsg) (err Error) {
w.Time[0] = uint32(atoi(f[1]))
w.Time[1] = uint32(atoi(f[2]))
w.Time[2] = uint32(atoi(f[3]))
- w.Msg = string(f[4])
+ w.Msg = cstring(f[4])
return
}
@@ -327,11 +338,6 @@ func Getgroups() (gids []int, err Error) {
return make([]int, 0), nil
}
-// TODO
-func Sendfile(outfd int, infd int, offset *int64, count int) (written int, errno int) {
- return -1, ENOSYS
-}
-
//sys Dup(oldfd int, newfd int) (fd int, err Error)
//sys Open(path string, mode int) (fd int, err Error)
//sys Create(path string, mode int, perm uint32) (fd int, err Error)
diff --git a/src/pkg/syscall/syscall_unix.go b/src/pkg/syscall/syscall_unix.go
index a77e40bc6..20c8a135f 100644
--- a/src/pkg/syscall/syscall_unix.go
+++ b/src/pkg/syscall/syscall_unix.go
@@ -4,12 +4,20 @@
package syscall
+import (
+ "sync"
+ "unsafe"
+)
+
+
var (
Stdin = 0
Stdout = 1
Stderr = 2
)
+const darwinAMD64 = OS == "darwin" && ARCH == "amd64"
+
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
@@ -21,3 +29,63 @@ func Errstr(errno int) string {
}
return errors[errno]
}
+
+// Mmap manager, for use by operating system-specific implementations.
+
+type mmapper struct {
+ sync.Mutex
+ active map[*byte][]byte // active mappings; key is last byte in mapping
+ mmap func(addr, length uintptr, prot, flags, fd int, offset int64) (uintptr, int)
+ munmap func(addr uintptr, length uintptr) int
+}
+
+func (m *mmapper) Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, errno int) {
+ if length <= 0 {
+ return nil, EINVAL
+ }
+
+ // Map the requested memory.
+ addr, errno := m.mmap(0, uintptr(length), prot, flags, fd, offset)
+ if errno != 0 {
+ return nil, errno
+ }
+
+ // Slice memory layout
+ var sl = struct {
+ addr uintptr
+ len int
+ cap int
+ }{addr, length, length}
+
+ // Use unsafe to turn sl into a []byte.
+ b := *(*[]byte)(unsafe.Pointer(&sl))
+
+ // Register mapping in m and return it.
+ p := &b[cap(b)-1]
+ m.Lock()
+ defer m.Unlock()
+ m.active[p] = b
+ return b, 0
+}
+
+func (m *mmapper) Munmap(data []byte) (errno int) {
+ if len(data) == 0 || len(data) != cap(data) {
+ return EINVAL
+ }
+
+ // Find the base of the mapping.
+ p := &data[cap(data)-1]
+ m.Lock()
+ defer m.Unlock()
+ b := m.active[p]
+ if b == nil || &b[0] != &data[0] {
+ return EINVAL
+ }
+
+ // Unmap the memory and update m.
+ if errno := m.munmap(uintptr(unsafe.Pointer(&b[0])), uintptr(len(b))); errno != 0 {
+ return errno
+ }
+ m.active[p] = nil, false
+ return 0
+}
diff --git a/src/pkg/syscall/syscall_windows.go b/src/pkg/syscall/syscall_windows.go
index d01664d12..0e979ff6b 100644
--- a/src/pkg/syscall/syscall_windows.go
+++ b/src/pkg/syscall/syscall_windows.go
@@ -173,6 +173,7 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, errno
//sys FlushViewOfFile(addr uintptr, length uintptr) (errno int)
//sys VirtualLock(addr uintptr, length uintptr) (errno int)
//sys VirtualUnlock(addr uintptr, length uintptr) (errno int)
+//sys TransmitFile(s int32, handle int32, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (errno int) = wsock32.TransmitFile
// syscall interface implementation for other packages
@@ -467,6 +468,7 @@ func Chmod(path string, mode uint32) (errno int) {
//sys WSAStartup(verreq uint32, data *WSAData) (sockerrno int) = wsock32.WSAStartup
//sys WSACleanup() (errno int) [failretval==-1] = wsock32.WSACleanup
+//sys WSAIoctl(s int32, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *Overlapped, completionRoutine uintptr) (errno int) [failretval==-1] = ws2_32.WSAIoctl
//sys socket(af int32, typ int32, protocol int32) (handle int32, errno int) [failretval==-1] = wsock32.socket
//sys setsockopt(s int32, level int32, optname int32, optval *byte, optlen int32) (errno int) [failretval==-1] = wsock32.setsockopt
//sys bind(s int32, name uintptr, namelen int32) (errno int) [failretval==-1] = wsock32.bind
@@ -487,6 +489,8 @@ func Chmod(path string, mode uint32) (errno int) {
//sys Ntohs(netshort uint16) (u uint16) = ws2_32.ntohs
//sys DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status uint32) = dnsapi.DnsQuery_W
//sys DnsRecordListFree(rl *DNSRecord, freetype uint32) = dnsapi.DnsRecordListFree
+//sys GetIfEntry(pIfRow *MibIfRow) (errcode int) = iphlpapi.GetIfEntry
+//sys GetAdaptersInfo(ai *IpAdapterInfo, ol *uint32) (errcode int) = iphlpapi.GetAdaptersInfo
// For testing: clients can set this flag to force
// creation of IPv6 sockets to return EAFNOSUPPORT.
diff --git a/src/pkg/syscall/types_linux.c b/src/pkg/syscall/types_linux.c
index ce7f96764..abb2a91a7 100644
--- a/src/pkg/syscall/types_linux.c
+++ b/src/pkg/syscall/types_linux.c
@@ -38,6 +38,7 @@ Input to godefs. See also mkerrors.sh and mkall.sh
#include <sys/user.h>
#include <sys/utsname.h>
#include <sys/wait.h>
+#include <linux/filter.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <time.h>
@@ -225,6 +226,16 @@ typedef struct ifaddrmsg $IfAddrmsg;
typedef struct rtmsg $RtMsg;
typedef struct rtnexthop $RtNexthop;
+// Linux socket filter
+
+enum {
+ $SizeofSockFilter = sizeof(struct sock_filter),
+ $SizeofSockFprog = sizeof(struct sock_fprog),
+};
+
+typedef struct sock_filter $SockFilter;
+typedef struct sock_fprog $SockFprog;
+
// Inotify
typedef struct inotify_event $InotifyEvent;
diff --git a/src/pkg/syscall/types_plan9.c b/src/pkg/syscall/types_plan9.c
index 6308ce08b..1da9d377c 100644
--- a/src/pkg/syscall/types_plan9.c
+++ b/src/pkg/syscall/types_plan9.c
@@ -19,20 +19,18 @@ enum {
OREAD = 0, // open for read
OWRITE = 1, // write
ORDWR = 2, // read and write
-
- $O_RDONLY = OREAD,
- $O_WRONLY = OWRITE,
- $O_RDWR = ORDWR,
-
OEXEC = 3, // execute, == read but check execute permission
OTRUNC = 16, // or'ed in (except for exec), truncate file first
OCEXEC = 32, // or'ed in, close on exec
-
- $O_CLOEXEC = OCEXEC,
-
ORCLOSE = 64, // or'ed in, remove on close
OEXCL = 0x1000, // or'ed in, exclusive use (create only)
- $O_EXCL = OEXCL,
+
+ $O_RDONLY = OREAD,
+ $O_WRONLY = OWRITE,
+ $O_RDWR = ORDWR,
+ $O_TRUNC = OTRUNC,
+ $O_CLOEXEC = OCEXEC,
+ $O_EXCL = OEXCL,
$STATMAX = 65535U,
$ERRMAX = 128,
diff --git a/src/pkg/syscall/zerrors_darwin_386.go b/src/pkg/syscall/zerrors_darwin_386.go
index 5ee64ee70..964e58878 100644
--- a/src/pkg/syscall/zerrors_darwin_386.go
+++ b/src/pkg/syscall/zerrors_darwin_386.go
@@ -709,6 +709,24 @@ const (
PROT_NONE = 0
PROT_READ = 0x1
PROT_WRITE = 0x2
+ PT_ATTACH = 0xa
+ PT_ATTACHEXC = 0xe
+ PT_CONTINUE = 0x7
+ PT_DENY_ATTACH = 0x1f
+ PT_DETACH = 0xb
+ PT_FIRSTMACH = 0x20
+ PT_FORCEQUOTA = 0x1e
+ PT_KILL = 0x8
+ PT_READ_D = 0x2
+ PT_READ_I = 0x1
+ PT_READ_U = 0x3
+ PT_SIGEXC = 0xc
+ PT_STEP = 0x9
+ PT_THUPDATE = 0xd
+ PT_TRACE_ME = 0
+ PT_WRITE_D = 0x5
+ PT_WRITE_I = 0x4
+ PT_WRITE_U = 0x6
RTAX_AUTHOR = 0x6
RTAX_BRD = 0x7
RTAX_DST = 0
diff --git a/src/pkg/syscall/zerrors_darwin_amd64.go b/src/pkg/syscall/zerrors_darwin_amd64.go
index 65a48d6e7..adf039905 100644
--- a/src/pkg/syscall/zerrors_darwin_amd64.go
+++ b/src/pkg/syscall/zerrors_darwin_amd64.go
@@ -1,7 +1,7 @@
-// mkerrors.sh
+// mkerrors.sh -f -m64
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
-// godefs -c gcc -gsyscall _const.c
+// godefs -c gcc -f -m64 -gsyscall -f -m64 _const.c
// MACHINE GENERATED - DO NOT EDIT.
@@ -709,6 +709,24 @@ const (
PROT_NONE = 0
PROT_READ = 0x1
PROT_WRITE = 0x2
+ PT_ATTACH = 0xa
+ PT_ATTACHEXC = 0xe
+ PT_CONTINUE = 0x7
+ PT_DENY_ATTACH = 0x1f
+ PT_DETACH = 0xb
+ PT_FIRSTMACH = 0x20
+ PT_FORCEQUOTA = 0x1e
+ PT_KILL = 0x8
+ PT_READ_D = 0x2
+ PT_READ_I = 0x1
+ PT_READ_U = 0x3
+ PT_SIGEXC = 0xc
+ PT_STEP = 0x9
+ PT_THUPDATE = 0xd
+ PT_TRACE_ME = 0
+ PT_WRITE_D = 0x5
+ PT_WRITE_I = 0x4
+ PT_WRITE_U = 0x6
RTAX_AUTHOR = 0x6
RTAX_BRD = 0x7
RTAX_DST = 0
diff --git a/src/pkg/syscall/zerrors_linux_386.go b/src/pkg/syscall/zerrors_linux_386.go
index 73caed44c..8d315813d 100644
--- a/src/pkg/syscall/zerrors_linux_386.go
+++ b/src/pkg/syscall/zerrors_linux_386.go
@@ -106,6 +106,46 @@ const (
ARPHRD_TUNNEL6 = 0x301
ARPHRD_VOID = 0xffff
ARPHRD_X25 = 0x10f
+ BPF_A = 0x10
+ BPF_ABS = 0x20
+ BPF_ADD = 0
+ BPF_ALU = 0x4
+ BPF_AND = 0x50
+ BPF_B = 0x10
+ BPF_DIV = 0x30
+ BPF_H = 0x8
+ BPF_IMM = 0
+ BPF_IND = 0x40
+ BPF_JA = 0
+ BPF_JEQ = 0x10
+ BPF_JGE = 0x30
+ BPF_JGT = 0x20
+ BPF_JMP = 0x5
+ BPF_JSET = 0x40
+ BPF_K = 0
+ BPF_LD = 0
+ BPF_LDX = 0x1
+ BPF_LEN = 0x80
+ BPF_LSH = 0x60
+ BPF_MAJOR_VERSION = 0x1
+ BPF_MAXINSNS = 0x1000
+ BPF_MEM = 0x60
+ BPF_MEMWORDS = 0x10
+ BPF_MINOR_VERSION = 0x1
+ BPF_MISC = 0x7
+ BPF_MSH = 0xa0
+ BPF_MUL = 0x20
+ BPF_NEG = 0x80
+ BPF_OR = 0x40
+ BPF_RET = 0x6
+ BPF_RSH = 0x70
+ BPF_ST = 0x2
+ BPF_STX = 0x3
+ BPF_SUB = 0x10
+ BPF_TAX = 0
+ BPF_TXA = 0x80
+ BPF_W = 0
+ BPF_X = 0x8
DT_BLK = 0x6
DT_CHR = 0x2
DT_DIR = 0x4
@@ -256,6 +296,68 @@ const (
ESRMNT = 0x45
ESTALE = 0x74
ESTRPIPE = 0x56
+ ETH_P_1588 = 0x88f7
+ ETH_P_8021Q = 0x8100
+ ETH_P_802_2 = 0x4
+ ETH_P_802_3 = 0x1
+ ETH_P_AARP = 0x80f3
+ ETH_P_ALL = 0x3
+ ETH_P_AOE = 0x88a2
+ ETH_P_ARCNET = 0x1a
+ ETH_P_ARP = 0x806
+ ETH_P_ATALK = 0x809b
+ ETH_P_ATMFATE = 0x8884
+ ETH_P_ATMMPOA = 0x884c
+ ETH_P_AX25 = 0x2
+ ETH_P_BPQ = 0x8ff
+ ETH_P_CAN = 0xc
+ ETH_P_CONTROL = 0x16
+ ETH_P_CUST = 0x6006
+ ETH_P_DDCMP = 0x6
+ ETH_P_DEC = 0x6000
+ ETH_P_DIAG = 0x6005
+ ETH_P_DNA_DL = 0x6001
+ ETH_P_DNA_RC = 0x6002
+ ETH_P_DNA_RT = 0x6003
+ ETH_P_DSA = 0x1b
+ ETH_P_ECONET = 0x18
+ ETH_P_EDSA = 0xdada
+ ETH_P_FCOE = 0x8906
+ ETH_P_FIP = 0x8914
+ ETH_P_HDLC = 0x19
+ ETH_P_IEEE802154 = 0xf6
+ ETH_P_IEEEPUP = 0xa00
+ ETH_P_IEEEPUPAT = 0xa01
+ ETH_P_IP = 0x800
+ ETH_P_IPV6 = 0x86dd
+ ETH_P_IPX = 0x8137
+ ETH_P_IRDA = 0x17
+ ETH_P_LAT = 0x6004
+ ETH_P_LOCALTALK = 0x9
+ ETH_P_LOOP = 0x60
+ ETH_P_MOBITEX = 0x15
+ ETH_P_MPLS_MC = 0x8848
+ ETH_P_MPLS_UC = 0x8847
+ ETH_P_PAE = 0x888e
+ ETH_P_PAUSE = 0x8808
+ ETH_P_PHONET = 0xf5
+ ETH_P_PPPTALK = 0x10
+ ETH_P_PPP_DISC = 0x8863
+ ETH_P_PPP_MP = 0x8
+ ETH_P_PPP_SES = 0x8864
+ ETH_P_PUP = 0x200
+ ETH_P_PUPAT = 0x201
+ ETH_P_RARP = 0x8035
+ ETH_P_SCA = 0x6007
+ ETH_P_SLOW = 0x8809
+ ETH_P_SNAP = 0x5
+ ETH_P_TEB = 0x6558
+ ETH_P_TIPC = 0x88ca
+ ETH_P_TRAILER = 0x1c
+ ETH_P_TR_802_2 = 0x11
+ ETH_P_WAN_PPP = 0x7
+ ETH_P_WCCP = 0x883e
+ ETH_P_X25 = 0x805
ETIME = 0x3e
ETIMEDOUT = 0x6e
ETOOMANYREFS = 0x6d
diff --git a/src/pkg/syscall/zerrors_linux_amd64.go b/src/pkg/syscall/zerrors_linux_amd64.go
index 89260740d..8f9147818 100644
--- a/src/pkg/syscall/zerrors_linux_amd64.go
+++ b/src/pkg/syscall/zerrors_linux_amd64.go
@@ -106,6 +106,46 @@ const (
ARPHRD_TUNNEL6 = 0x301
ARPHRD_VOID = 0xffff
ARPHRD_X25 = 0x10f
+ BPF_A = 0x10
+ BPF_ABS = 0x20
+ BPF_ADD = 0
+ BPF_ALU = 0x4
+ BPF_AND = 0x50
+ BPF_B = 0x10
+ BPF_DIV = 0x30
+ BPF_H = 0x8
+ BPF_IMM = 0
+ BPF_IND = 0x40
+ BPF_JA = 0
+ BPF_JEQ = 0x10
+ BPF_JGE = 0x30
+ BPF_JGT = 0x20
+ BPF_JMP = 0x5
+ BPF_JSET = 0x40
+ BPF_K = 0
+ BPF_LD = 0
+ BPF_LDX = 0x1
+ BPF_LEN = 0x80
+ BPF_LSH = 0x60
+ BPF_MAJOR_VERSION = 0x1
+ BPF_MAXINSNS = 0x1000
+ BPF_MEM = 0x60
+ BPF_MEMWORDS = 0x10
+ BPF_MINOR_VERSION = 0x1
+ BPF_MISC = 0x7
+ BPF_MSH = 0xa0
+ BPF_MUL = 0x20
+ BPF_NEG = 0x80
+ BPF_OR = 0x40
+ BPF_RET = 0x6
+ BPF_RSH = 0x70
+ BPF_ST = 0x2
+ BPF_STX = 0x3
+ BPF_SUB = 0x10
+ BPF_TAX = 0
+ BPF_TXA = 0x80
+ BPF_W = 0
+ BPF_X = 0x8
DT_BLK = 0x6
DT_CHR = 0x2
DT_DIR = 0x4
@@ -256,6 +296,68 @@ const (
ESRMNT = 0x45
ESTALE = 0x74
ESTRPIPE = 0x56
+ ETH_P_1588 = 0x88f7
+ ETH_P_8021Q = 0x8100
+ ETH_P_802_2 = 0x4
+ ETH_P_802_3 = 0x1
+ ETH_P_AARP = 0x80f3
+ ETH_P_ALL = 0x3
+ ETH_P_AOE = 0x88a2
+ ETH_P_ARCNET = 0x1a
+ ETH_P_ARP = 0x806
+ ETH_P_ATALK = 0x809b
+ ETH_P_ATMFATE = 0x8884
+ ETH_P_ATMMPOA = 0x884c
+ ETH_P_AX25 = 0x2
+ ETH_P_BPQ = 0x8ff
+ ETH_P_CAN = 0xc
+ ETH_P_CONTROL = 0x16
+ ETH_P_CUST = 0x6006
+ ETH_P_DDCMP = 0x6
+ ETH_P_DEC = 0x6000
+ ETH_P_DIAG = 0x6005
+ ETH_P_DNA_DL = 0x6001
+ ETH_P_DNA_RC = 0x6002
+ ETH_P_DNA_RT = 0x6003
+ ETH_P_DSA = 0x1b
+ ETH_P_ECONET = 0x18
+ ETH_P_EDSA = 0xdada
+ ETH_P_FCOE = 0x8906
+ ETH_P_FIP = 0x8914
+ ETH_P_HDLC = 0x19
+ ETH_P_IEEE802154 = 0xf6
+ ETH_P_IEEEPUP = 0xa00
+ ETH_P_IEEEPUPAT = 0xa01
+ ETH_P_IP = 0x800
+ ETH_P_IPV6 = 0x86dd
+ ETH_P_IPX = 0x8137
+ ETH_P_IRDA = 0x17
+ ETH_P_LAT = 0x6004
+ ETH_P_LOCALTALK = 0x9
+ ETH_P_LOOP = 0x60
+ ETH_P_MOBITEX = 0x15
+ ETH_P_MPLS_MC = 0x8848
+ ETH_P_MPLS_UC = 0x8847
+ ETH_P_PAE = 0x888e
+ ETH_P_PAUSE = 0x8808
+ ETH_P_PHONET = 0xf5
+ ETH_P_PPPTALK = 0x10
+ ETH_P_PPP_DISC = 0x8863
+ ETH_P_PPP_MP = 0x8
+ ETH_P_PPP_SES = 0x8864
+ ETH_P_PUP = 0x200
+ ETH_P_PUPAT = 0x201
+ ETH_P_RARP = 0x8035
+ ETH_P_SCA = 0x6007
+ ETH_P_SLOW = 0x8809
+ ETH_P_SNAP = 0x5
+ ETH_P_TEB = 0x6558
+ ETH_P_TIPC = 0x88ca
+ ETH_P_TRAILER = 0x1c
+ ETH_P_TR_802_2 = 0x11
+ ETH_P_WAN_PPP = 0x7
+ ETH_P_WCCP = 0x883e
+ ETH_P_X25 = 0x805
ETIME = 0x3e
ETIMEDOUT = 0x6e
ETOOMANYREFS = 0x6d
diff --git a/src/pkg/syscall/zerrors_linux_arm.go b/src/pkg/syscall/zerrors_linux_arm.go
index 50cdaf18a..64a74c0ff 100644
--- a/src/pkg/syscall/zerrors_linux_arm.go
+++ b/src/pkg/syscall/zerrors_linux_arm.go
@@ -106,6 +106,46 @@ const (
ARPHRD_TUNNEL6 = 0x301
ARPHRD_VOID = 0xffff
ARPHRD_X25 = 0x10f
+ BPF_A = 0x10
+ BPF_ABS = 0x20
+ BPF_ADD = 0
+ BPF_ALU = 0x4
+ BPF_AND = 0x50
+ BPF_B = 0x10
+ BPF_DIV = 0x30
+ BPF_H = 0x8
+ BPF_IMM = 0
+ BPF_IND = 0x40
+ BPF_JA = 0
+ BPF_JEQ = 0x10
+ BPF_JGE = 0x30
+ BPF_JGT = 0x20
+ BPF_JMP = 0x5
+ BPF_JSET = 0x40
+ BPF_K = 0
+ BPF_LD = 0
+ BPF_LDX = 0x1
+ BPF_LEN = 0x80
+ BPF_LSH = 0x60
+ BPF_MAJOR_VERSION = 0x1
+ BPF_MAXINSNS = 0x1000
+ BPF_MEM = 0x60
+ BPF_MEMWORDS = 0x10
+ BPF_MINOR_VERSION = 0x1
+ BPF_MISC = 0x7
+ BPF_MSH = 0xa0
+ BPF_MUL = 0x20
+ BPF_NEG = 0x80
+ BPF_OR = 0x40
+ BPF_RET = 0x6
+ BPF_RSH = 0x70
+ BPF_ST = 0x2
+ BPF_STX = 0x3
+ BPF_SUB = 0x10
+ BPF_TAX = 0
+ BPF_TXA = 0x80
+ BPF_W = 0
+ BPF_X = 0x8
DT_BLK = 0x6
DT_CHR = 0x2
DT_DIR = 0x4
@@ -258,6 +298,68 @@ const (
ESRMNT = 0x45
ESTALE = 0x74
ESTRPIPE = 0x56
+ ETH_P_1588 = 0x88f7
+ ETH_P_8021Q = 0x8100
+ ETH_P_802_2 = 0x4
+ ETH_P_802_3 = 0x1
+ ETH_P_AARP = 0x80f3
+ ETH_P_ALL = 0x3
+ ETH_P_AOE = 0x88a2
+ ETH_P_ARCNET = 0x1a
+ ETH_P_ARP = 0x806
+ ETH_P_ATALK = 0x809b
+ ETH_P_ATMFATE = 0x8884
+ ETH_P_ATMMPOA = 0x884c
+ ETH_P_AX25 = 0x2
+ ETH_P_BPQ = 0x8ff
+ ETH_P_CAN = 0xc
+ ETH_P_CONTROL = 0x16
+ ETH_P_CUST = 0x6006
+ ETH_P_DDCMP = 0x6
+ ETH_P_DEC = 0x6000
+ ETH_P_DIAG = 0x6005
+ ETH_P_DNA_DL = 0x6001
+ ETH_P_DNA_RC = 0x6002
+ ETH_P_DNA_RT = 0x6003
+ ETH_P_DSA = 0x1b
+ ETH_P_ECONET = 0x18
+ ETH_P_EDSA = 0xdada
+ ETH_P_FCOE = 0x8906
+ ETH_P_FIP = 0x8914
+ ETH_P_HDLC = 0x19
+ ETH_P_IEEE802154 = 0xf6
+ ETH_P_IEEEPUP = 0xa00
+ ETH_P_IEEEPUPAT = 0xa01
+ ETH_P_IP = 0x800
+ ETH_P_IPV6 = 0x86dd
+ ETH_P_IPX = 0x8137
+ ETH_P_IRDA = 0x17
+ ETH_P_LAT = 0x6004
+ ETH_P_LOCALTALK = 0x9
+ ETH_P_LOOP = 0x60
+ ETH_P_MOBITEX = 0x15
+ ETH_P_MPLS_MC = 0x8848
+ ETH_P_MPLS_UC = 0x8847
+ ETH_P_PAE = 0x888e
+ ETH_P_PAUSE = 0x8808
+ ETH_P_PHONET = 0xf5
+ ETH_P_PPPTALK = 0x10
+ ETH_P_PPP_DISC = 0x8863
+ ETH_P_PPP_MP = 0x8
+ ETH_P_PPP_SES = 0x8864
+ ETH_P_PUP = 0x200
+ ETH_P_PUPAT = 0x201
+ ETH_P_RARP = 0x8035
+ ETH_P_SCA = 0x6007
+ ETH_P_SLOW = 0x8809
+ ETH_P_SNAP = 0x5
+ ETH_P_TEB = 0x6558
+ ETH_P_TIPC = 0x88ca
+ ETH_P_TRAILER = 0x1c
+ ETH_P_TR_802_2 = 0x11
+ ETH_P_WAN_PPP = 0x7
+ ETH_P_WCCP = 0x883e
+ ETH_P_X25 = 0x805
ETIME = 0x3e
ETIMEDOUT = 0x6e
ETOOMANYREFS = 0x6d
@@ -696,6 +798,9 @@ const (
PTRACE_SINGLESTEP = 0x9
PTRACE_SYSCALL = 0x18
PTRACE_TRACEME = 0
+ PT_DATA_ADDR = 0x10004
+ PT_TEXT_ADDR = 0x10000
+ PT_TEXT_END_ADDR = 0x10008
RTAX_ADVMSS = 0x8
RTAX_CWND = 0x7
RTAX_FEATURES = 0xc
diff --git a/src/pkg/syscall/zerrors_plan9_386.go b/src/pkg/syscall/zerrors_plan9_386.go
index 78b5c72bb..e452079f5 100644
--- a/src/pkg/syscall/zerrors_plan9_386.go
+++ b/src/pkg/syscall/zerrors_plan9_386.go
@@ -4,10 +4,9 @@ package syscall
const (
// Invented values to support what package os expects.
O_CREAT = 0x02000
+ O_APPEND = 0x00400
O_NOCTTY = 0x00000
- O_TRUNC = 0x00000
O_NONBLOCK = 0x00000
- O_APPEND = 0x00000
O_SYNC = 0x00000
O_ASYNC = 0x00000
diff --git a/src/pkg/syscall/zsyscall_darwin_386.go b/src/pkg/syscall/zsyscall_darwin_386.go
index 2f5b2703b..436953eca 100644
--- a/src/pkg/syscall/zsyscall_darwin_386.go
+++ b/src/pkg/syscall/zsyscall_darwin_386.go
@@ -85,7 +85,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (errn
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen int) (errno int) {
+func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (errno int) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
errno = int(e1)
return
@@ -154,6 +154,23 @@ func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (errno i
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func recvmsg(s int, msg *Msghdr, flags int) (n int, errno int) {
+ r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sendmsg(s int, msg *Msghdr, flags int) (errno int) {
+ _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, errno int) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
@@ -219,6 +236,14 @@ func munmap(addr uintptr, length uintptr) (errno int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func ptrace(request int, pid int, addr uintptr, data uintptr) (errno int) {
+ _, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func kill(pid int, signum int, posix int) (errno int) {
_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), uintptr(posix))
errno = int(e1)
diff --git a/src/pkg/syscall/zsyscall_darwin_amd64.go b/src/pkg/syscall/zsyscall_darwin_amd64.go
index 995c710b4..1ba4c3cfe 100644
--- a/src/pkg/syscall/zsyscall_darwin_amd64.go
+++ b/src/pkg/syscall/zsyscall_darwin_amd64.go
@@ -85,7 +85,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (errn
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen int) (errno int) {
+func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (errno int) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
errno = int(e1)
return
@@ -154,6 +154,23 @@ func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (errno i
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func recvmsg(s int, msg *Msghdr, flags int) (n int, errno int) {
+ r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sendmsg(s int, msg *Msghdr, flags int) (errno int) {
+ _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, errno int) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
@@ -219,6 +236,14 @@ func munmap(addr uintptr, length uintptr) (errno int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func ptrace(request int, pid int, addr uintptr, data uintptr) (errno int) {
+ _, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func kill(pid int, signum int, posix int) (errno int) {
_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), uintptr(posix))
errno = int(e1)
diff --git a/src/pkg/syscall/zsyscall_freebsd_386.go b/src/pkg/syscall/zsyscall_freebsd_386.go
index 0ffb9a4b9..d152e4380 100644
--- a/src/pkg/syscall/zsyscall_freebsd_386.go
+++ b/src/pkg/syscall/zsyscall_freebsd_386.go
@@ -85,7 +85,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (errn
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen int) (errno int) {
+func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (errno int) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
errno = int(e1)
return
@@ -154,6 +154,23 @@ func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (errno i
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func recvmsg(s int, msg *Msghdr, flags int) (n int, errno int) {
+ r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sendmsg(s int, msg *Msghdr, flags int) (errno int) {
+ _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, errno int) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
diff --git a/src/pkg/syscall/zsyscall_freebsd_amd64.go b/src/pkg/syscall/zsyscall_freebsd_amd64.go
index 38a06ae3b..156b087e3 100644
--- a/src/pkg/syscall/zsyscall_freebsd_amd64.go
+++ b/src/pkg/syscall/zsyscall_freebsd_amd64.go
@@ -85,7 +85,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (errn
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen int) (errno int) {
+func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (errno int) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
errno = int(e1)
return
@@ -154,6 +154,23 @@ func sendto(s int, buf []byte, flags int, to uintptr, addrlen _Socklen) (errno i
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func recvmsg(s int, msg *Msghdr, flags int) (n int, errno int) {
+ r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sendmsg(s int, msg *Msghdr, flags int) (errno int) {
+ _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, errno int) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
diff --git a/src/pkg/syscall/zsyscall_linux_amd64.go b/src/pkg/syscall/zsyscall_linux_amd64.go
index d6e287967..fa20ff57a 100644
--- a/src/pkg/syscall/zsyscall_linux_amd64.go
+++ b/src/pkg/syscall/zsyscall_linux_amd64.go
@@ -1169,7 +1169,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (errn
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen int) (errno int) {
+func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (errno int) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
errno = int(e1)
return
diff --git a/src/pkg/syscall/zsyscall_linux_arm.go b/src/pkg/syscall/zsyscall_linux_arm.go
index af5f7c50c..560a65b12 100644
--- a/src/pkg/syscall/zsyscall_linux_arm.go
+++ b/src/pkg/syscall/zsyscall_linux_arm.go
@@ -895,7 +895,7 @@ func getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (errn
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func setsockopt(s int, level int, name int, val uintptr, vallen int) (errno int) {
+func setsockopt(s int, level int, name int, val uintptr, vallen uintptr) (errno int) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
errno = int(e1)
return
diff --git a/src/pkg/syscall/zsyscall_windows_386.go b/src/pkg/syscall/zsyscall_windows_386.go
index 447b09043..fd28d338c 100644
--- a/src/pkg/syscall/zsyscall_windows_386.go
+++ b/src/pkg/syscall/zsyscall_windows_386.go
@@ -1,4 +1,4 @@
-// mksyscall_windows.pl -l32 syscall_windows.go syscall_windows_386.go
+// mksyscall_windows.pl
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
package syscall
@@ -12,6 +12,7 @@ var (
modwsock32 = loadDll("wsock32.dll")
modws2_32 = loadDll("ws2_32.dll")
moddnsapi = loadDll("dnsapi.dll")
+ modiphlpapi = loadDll("iphlpapi.dll")
procGetLastError = getSysProcAddr(modkernel32, "GetLastError")
procLoadLibraryW = getSysProcAddr(modkernel32, "LoadLibraryW")
@@ -77,8 +78,10 @@ var (
procFlushViewOfFile = getSysProcAddr(modkernel32, "FlushViewOfFile")
procVirtualLock = getSysProcAddr(modkernel32, "VirtualLock")
procVirtualUnlock = getSysProcAddr(modkernel32, "VirtualUnlock")
+ procTransmitFile = getSysProcAddr(modwsock32, "TransmitFile")
procWSAStartup = getSysProcAddr(modwsock32, "WSAStartup")
procWSACleanup = getSysProcAddr(modwsock32, "WSACleanup")
+ procWSAIoctl = getSysProcAddr(modws2_32, "WSAIoctl")
procsocket = getSysProcAddr(modwsock32, "socket")
procsetsockopt = getSysProcAddr(modwsock32, "setsockopt")
procbind = getSysProcAddr(modwsock32, "bind")
@@ -99,6 +102,8 @@ var (
procntohs = getSysProcAddr(modws2_32, "ntohs")
procDnsQuery_W = getSysProcAddr(moddnsapi, "DnsQuery_W")
procDnsRecordListFree = getSysProcAddr(moddnsapi, "DnsRecordListFree")
+ procGetIfEntry = getSysProcAddr(modiphlpapi, "GetIfEntry")
+ procGetAdaptersInfo = getSysProcAddr(modiphlpapi, "GetAdaptersInfo")
)
func GetLastError() (lasterrno int) {
@@ -1008,6 +1013,20 @@ func VirtualUnlock(addr uintptr, length uintptr) (errno int) {
return
}
+func TransmitFile(s int32, handle int32, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (errno int) {
+ r1, _, e1 := Syscall9(procTransmitFile, 7, uintptr(s), uintptr(handle), uintptr(bytesToWrite), uintptr(bytsPerSend), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(transmitFileBuf)), uintptr(flags), 0, 0)
+ if int(r1) == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
func WSAStartup(verreq uint32, data *WSAData) (sockerrno int) {
r0, _, _ := Syscall(procWSAStartup, 2, uintptr(verreq), uintptr(unsafe.Pointer(data)), 0)
sockerrno = int(r0)
@@ -1028,6 +1047,20 @@ func WSACleanup() (errno int) {
return
}
+func WSAIoctl(s int32, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *Overlapped, completionRoutine uintptr) (errno int) {
+ r1, _, e1 := Syscall9(procWSAIoctl, 9, uintptr(s), uintptr(iocc), uintptr(unsafe.Pointer(inbuf)), uintptr(cbif), uintptr(unsafe.Pointer(outbuf)), uintptr(cbob), uintptr(unsafe.Pointer(cbbr)), uintptr(unsafe.Pointer(overlapped)), uintptr(completionRoutine))
+ if int(r1) == -1 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
func socket(af int32, typ int32, protocol int32) (handle int32, errno int) {
r0, _, e1 := Syscall(procsocket, 3, uintptr(af), uintptr(typ), uintptr(protocol))
handle = int32(r0)
@@ -1276,3 +1309,15 @@ func DnsRecordListFree(rl *DNSRecord, freetype uint32) {
Syscall(procDnsRecordListFree, 2, uintptr(unsafe.Pointer(rl)), uintptr(freetype), 0)
return
}
+
+func GetIfEntry(pIfRow *MibIfRow) (errcode int) {
+ r0, _, _ := Syscall(procGetIfEntry, 1, uintptr(unsafe.Pointer(pIfRow)), 0, 0)
+ errcode = int(r0)
+ return
+}
+
+func GetAdaptersInfo(ai *IpAdapterInfo, ol *uint32) (errcode int) {
+ r0, _, _ := Syscall(procGetAdaptersInfo, 2, uintptr(unsafe.Pointer(ai)), uintptr(unsafe.Pointer(ol)), 0)
+ errcode = int(r0)
+ return
+}
diff --git a/src/pkg/syscall/zsysnum_darwin_386.go b/src/pkg/syscall/zsysnum_darwin_386.go
index 8d5c93478..50aec39f1 100644
--- a/src/pkg/syscall/zsysnum_darwin_386.go
+++ b/src/pkg/syscall/zsysnum_darwin_386.go
@@ -1,485 +1,355 @@
-// mksysnum_darwin.sh /home/rsc/pub/xnu-1228/bsd/kern/syscalls.master
+// mksysnum_darwin.pl /usr/include/sys/syscall.h
// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
package syscall
const (
- // SYS_NOSYS = 0; // { int nosys(void); } { indirect syscall }
- SYS_EXIT = 1 // { void exit(int rval); }
- SYS_FORK = 2 // { int fork(void); }
- SYS_READ = 3 // { user_ssize_t read(int fd, user_addr_t cbuf, user_size_t nbyte); }
- SYS_WRITE = 4 // { user_ssize_t write(int fd, user_addr_t cbuf, user_size_t nbyte); }
- SYS_OPEN = 5 // { int open(user_addr_t path, int flags, int mode); }
- SYS_CLOSE = 6 // { int close(int fd); }
- SYS_WAIT4 = 7 // { int wait4(int pid, user_addr_t status, int options, user_addr_t rusage); }
- // SYS_NOSYS = 8; // { int nosys(void); } { old creat }
- SYS_LINK = 9 // { int link(user_addr_t path, user_addr_t link); }
- SYS_UNLINK = 10 // { int unlink(user_addr_t path); }
- // SYS_NOSYS = 11; // { int nosys(void); } { old execv }
- SYS_CHDIR = 12 // { int chdir(user_addr_t path); }
- SYS_FCHDIR = 13 // { int fchdir(int fd); }
- SYS_MKNOD = 14 // { int mknod(user_addr_t path, int mode, int dev); }
- SYS_CHMOD = 15 // { int chmod(user_addr_t path, int mode); }
- SYS_CHOWN = 16 // { int chown(user_addr_t path, int uid, int gid); }
- SYS_OGETFSSTAT = 18 // { int ogetfsstat(user_addr_t buf, int bufsize, int flags); }
- SYS_GETFSSTAT = 18 // { int getfsstat(user_addr_t buf, int bufsize, int flags); }
- // SYS_NOSYS = 19; // { int nosys(void); } { old lseek }
- SYS_GETPID = 20 // { int getpid(void); }
- // SYS_NOSYS = 21; // { int nosys(void); } { old mount }
- // SYS_NOSYS = 22; // { int nosys(void); } { old umount }
- SYS_SETUID = 23 // { int setuid(uid_t uid); }
- SYS_GETUID = 24 // { int getuid(void); }
- SYS_GETEUID = 25 // { int geteuid(void); }
- SYS_PTRACE = 26 // { int ptrace(int req, pid_t pid, caddr_t addr, int data); }
- SYS_RECVMSG = 27 // { int recvmsg(int s, struct msghdr *msg, int flags); }
- SYS_SENDMSG = 28 // { int sendmsg(int s, caddr_t msg, int flags); }
- SYS_RECVFROM = 29 // { int recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, int *fromlenaddr); }
- SYS_ACCEPT = 30 // { int accept(int s, caddr_t name, socklen_t *anamelen); }
- SYS_GETPEERNAME = 31 // { int getpeername(int fdes, caddr_t asa, socklen_t *alen); }
- SYS_GETSOCKNAME = 32 // { int getsockname(int fdes, caddr_t asa, socklen_t *alen); }
- // SYS_NOSYS = 27; // { int nosys(void); }
- // SYS_NOSYS = 28; // { int nosys(void); }
- // SYS_NOSYS = 29; // { int nosys(void); }
- // SYS_NOSYS = 30; // { int nosys(void); }
- // SYS_NOSYS = 31; // { int nosys(void); }
- // SYS_NOSYS = 32; // { int nosys(void); }
- SYS_ACCESS = 33 // { int access(user_addr_t path, int flags); }
- SYS_CHFLAGS = 34 // { int chflags(char *path, int flags); }
- SYS_FCHFLAGS = 35 // { int fchflags(int fd, int flags); }
- SYS_SYNC = 36 // { int sync(void); }
- SYS_KILL = 37 // { int kill(int pid, int signum, int posix); }
- // SYS_NOSYS = 38; // { int nosys(void); } { old stat }
- SYS_GETPPID = 39 // { int getppid(void); }
- // SYS_NOSYS = 40; // { int nosys(void); } { old lstat }
- SYS_DUP = 41 // { int dup(u_int fd); }
- SYS_PIPE = 42 // { int pipe(void); }
- SYS_GETEGID = 43 // { int getegid(void); }
- SYS_PROFIL = 44 // { int profil(short *bufbase, size_t bufsize, u_long pcoffset, u_int pcscale); }
- // SYS_NOSYS = 45; // { int nosys(void); } { old ktrace }
- SYS_SIGACTION = 46 // { int sigaction(int signum, struct __sigaction *nsa, struct sigaction *osa); }
- SYS_GETGID = 47 // { int getgid(void); }
- SYS_SIGPROCMASK = 48 // { int sigprocmask(int how, user_addr_t mask, user_addr_t omask); }
- SYS_GETLOGIN = 49 // { int getlogin(char *namebuf, u_int namelen); }
- SYS_SETLOGIN = 50 // { int setlogin(char *namebuf); }
- SYS_ACCT = 51 // { int acct(char *path); }
- SYS_SIGPENDING = 52 // { int sigpending(struct sigvec *osv); }
- SYS_SIGALTSTACK = 53 // { int sigaltstack(struct sigaltstack *nss, struct sigaltstack *oss); }
- SYS_IOCTL = 54 // { int ioctl(int fd, u_long com, caddr_t data); }
- SYS_REBOOT = 55 // { int reboot(int opt, char *command); }
- SYS_REVOKE = 56 // { int revoke(char *path); }
- SYS_SYMLINK = 57 // { int symlink(char *path, char *link); }
- SYS_READLINK = 58 // { int readlink(char *path, char *buf, int count); }
- SYS_EXECVE = 59 // { int execve(char *fname, char **argp, char **envp); }
- SYS_UMASK = 60 // { int umask(int newmask); }
- SYS_CHROOT = 61 // { int chroot(user_addr_t path); }
- // SYS_NOSYS = 62; // { int nosys(void); } { old fstat }
- // SYS_NOSYS = 63; // { int nosys(void); } { used internally, reserved }
- // SYS_NOSYS = 64; // { int nosys(void); } { old getpagesize }
- SYS_MSYNC = 65 // { int msync(caddr_t addr, size_t len, int flags); }
- SYS_VFORK = 66 // { int vfork(void); }
- // SYS_NOSYS = 67; // { int nosys(void); } { old vread }
- // SYS_NOSYS = 68; // { int nosys(void); } { old vwrite }
- SYS_SBRK = 69 // { int sbrk(int incr) NO_SYSCALL_STUB; }
- SYS_SSTK = 70 // { int sstk(int incr) NO_SYSCALL_STUB; }
- // SYS_NOSYS = 71; // { int nosys(void); } { old mmap }
- SYS_OVADVISE = 72 // { int ovadvise(void) NO_SYSCALL_STUB; } { old vadvise }
- SYS_MUNMAP = 73 // { int munmap(caddr_t addr, size_t len); }
- SYS_MPROTECT = 74 // { int mprotect(caddr_t addr, size_t len, int prot); }
- SYS_MADVISE = 75 // { int madvise(caddr_t addr, size_t len, int behav); }
- // SYS_NOSYS = 76; // { int nosys(void); } { old vhangup }
- // SYS_NOSYS = 77; // { int nosys(void); } { old vlimit }
- SYS_MINCORE = 78 // { int mincore(user_addr_t addr, user_size_t len, user_addr_t vec); }
- SYS_GETGROUPS = 79 // { int getgroups(u_int gidsetsize, gid_t *gidset); }
- SYS_SETGROUPS = 80 // { int setgroups(u_int gidsetsize, gid_t *gidset); }
- SYS_GETPGRP = 81 // { int getpgrp(void); }
- SYS_SETPGID = 82 // { int setpgid(int pid, int pgid); }
- SYS_SETITIMER = 83 // { int setitimer(u_int which, struct itimerval *itv, struct itimerval *oitv); }
- // SYS_NOSYS = 84; // { int nosys(void); } { old wait }
- SYS_SWAPON = 85 // { int swapon(void); }
- SYS_GETITIMER = 86 // { int getitimer(u_int which, struct itimerval *itv); }
- // SYS_NOSYS = 87; // { int nosys(void); } { old gethostname }
- // SYS_NOSYS = 88; // { int nosys(void); } { old sethostname }
- SYS_GETDTABLESIZE = 89 // { int getdtablesize(void); }
- SYS_DUP2 = 90 // { int dup2(u_int from, u_int to); }
- // SYS_NOSYS = 91; // { int nosys(void); } { old getdopt }
- SYS_FCNTL = 92 // { int fcntl(int fd, int cmd, long arg); }
- SYS_SELECT = 93 // { int select(int nd, u_int32_t *in, u_int32_t *ou, u_int32_t *ex, struct timeval *tv); }
- // SYS_NOSYS = 94; // { int nosys(void); } { old setdopt }
- SYS_FSYNC = 95 // { int fsync(int fd); }
- SYS_SETPRIORITY = 96 // { int setpriority(int which, id_t who, int prio); }
- SYS_SOCKET = 97 // { int socket(int domain, int type, int protocol); }
- SYS_CONNECT = 98 // { int connect(int s, caddr_t name, socklen_t namelen); }
- // SYS_NOSYS = 97; // { int nosys(void); }
- // SYS_NOSYS = 98; // { int nosys(void); }
- // SYS_NOSYS = 99; // { int nosys(void); } { old accept }
- SYS_GETPRIORITY = 100 // { int getpriority(int which, id_t who); }
- // SYS_NOSYS = 101; // { int nosys(void); } { old send }
- // SYS_NOSYS = 102; // { int nosys(void); } { old recv }
- // SYS_NOSYS = 103; // { int nosys(void); } { old sigreturn }
- SYS_BIND = 104 // { int bind(int s, caddr_t name, socklen_t namelen); }
- SYS_SETSOCKOPT = 105 // { int setsockopt(int s, int level, int name, caddr_t val, socklen_t valsize); }
- SYS_LISTEN = 106 // { int listen(int s, int backlog); }
- // SYS_NOSYS = 104; // { int nosys(void); }
- // SYS_NOSYS = 105; // { int nosys(void); }
- // SYS_NOSYS = 106; // { int nosys(void); }
- // SYS_NOSYS = 107; // { int nosys(void); } { old vtimes }
- // SYS_NOSYS = 108; // { int nosys(void); } { old sigvec }
- // SYS_NOSYS = 109; // { int nosys(void); } { old sigblock }
- // SYS_NOSYS = 110; // { int nosys(void); } { old sigsetmask }
- SYS_SIGSUSPEND = 111 // { int sigsuspend(sigset_t mask); }
- // SYS_NOSYS = 112; // { int nosys(void); } { old sigstack }
- // SYS_NOSYS = 113; // { int nosys(void); } { old recvmsg }
- // SYS_NOSYS = 114; // { int nosys(void); } { old sendmsg }
- // SYS_NOSYS = 113; // { int nosys(void); }
- // SYS_NOSYS = 114; // { int nosys(void); }
- // SYS_NOSYS = 115; // { int nosys(void); } { old vtrace }
- SYS_GETTIMEOFDAY = 116 // { int gettimeofday(struct timeval *tp, struct timezone *tzp); }
- SYS_GETRUSAGE = 117 // { int getrusage(int who, struct rusage *rusage); }
- SYS_GETSOCKOPT = 118 // { int getsockopt(int s, int level, int name, caddr_t val, socklen_t *avalsize); }
- // SYS_NOSYS = 118; // { int nosys(void); }
- // SYS_NOSYS = 119; // { int nosys(void); } { old resuba }
- SYS_READV = 120 // { user_ssize_t readv(int fd, struct iovec *iovp, u_int iovcnt); }
- SYS_WRITEV = 121 // { user_ssize_t writev(int fd, struct iovec *iovp, u_int iovcnt); }
- SYS_SETTIMEOFDAY = 122 // { int settimeofday(struct timeval *tv, struct timezone *tzp); }
- SYS_FCHOWN = 123 // { int fchown(int fd, int uid, int gid); }
- SYS_FCHMOD = 124 // { int fchmod(int fd, int mode); }
- // SYS_NOSYS = 125; // { int nosys(void); } { old recvfrom }
- SYS_SETREUID = 126 // { int setreuid(uid_t ruid, uid_t euid); }
- SYS_SETREGID = 127 // { int setregid(gid_t rgid, gid_t egid); }
- SYS_RENAME = 128 // { int rename(char *from, char *to); }
- // SYS_NOSYS = 129; // { int nosys(void); } { old truncate }
- // SYS_NOSYS = 130; // { int nosys(void); } { old ftruncate }
- SYS_FLOCK = 131 // { int flock(int fd, int how); }
- SYS_MKFIFO = 132 // { int mkfifo(user_addr_t path, int mode); }
- SYS_SENDTO = 133 // { int sendto(int s, caddr_t buf, size_t len, int flags, caddr_t to, socklen_t tolen); }
- SYS_SHUTDOWN = 134 // { int shutdown(int s, int how); }
- SYS_SOCKETPAIR = 135 // { int socketpair(int domain, int type, int protocol, int *rsv); }
- // SYS_NOSYS = 133; // { int nosys(void); }
- // SYS_NOSYS = 134; // { int nosys(void); }
- // SYS_NOSYS = 135; // { int nosys(void); }
- SYS_MKDIR = 136 // { int mkdir(user_addr_t path, int mode); }
- SYS_RMDIR = 137 // { int rmdir(char *path); }
- SYS_UTIMES = 138 // { int utimes(char *path, struct timeval *tptr); }
- SYS_FUTIMES = 139 // { int futimes(int fd, struct timeval *tptr); }
- SYS_ADJTIME = 140 // { int adjtime(struct timeval *delta, struct timeval *olddelta); }
- // SYS_NOSYS = 141; // { int nosys(void); } { old getpeername }
- SYS_GETHOSTUUID = 142 // { int gethostuuid(unsigned char *uuid_buf, const struct timespec *timeoutp); }
- // SYS_NOSYS = 143; // { int nosys(void); } { old sethostid }
- // SYS_NOSYS = 144; // { int nosys(void); } { old getrlimit }
- // SYS_NOSYS = 145; // { int nosys(void); } { old setrlimit }
- // SYS_NOSYS = 146; // { int nosys(void); } { old killpg }
- SYS_SETSID = 147 // { int setsid(void); }
- // SYS_NOSYS = 148; // { int nosys(void); } { old setquota }
- // SYS_NOSYS = 149; // { int nosys(void); } { old qquota }
- // SYS_NOSYS = 150; // { int nosys(void); } { old getsockname }
- SYS_GETPGID = 151 // { int getpgid(pid_t pid); }
- SYS_SETPRIVEXEC = 152 // { int setprivexec(int flag); }
- SYS_PREAD = 153 // { user_ssize_t pread(int fd, user_addr_t buf, user_size_t nbyte, off_t offset); }
- SYS_PWRITE = 154 // { user_ssize_t pwrite(int fd, user_addr_t buf, user_size_t nbyte, off_t offset); }
- SYS_NFSSVC = 155 // { int nfssvc(int flag, caddr_t argp); }
- // SYS_NOSYS = 155; // { int nosys(void); }
- // SYS_NOSYS = 156; // { int nosys(void); } { old getdirentries }
- SYS_STATFS = 157 // { int statfs(char *path, struct statfs *buf); }
- SYS_FSTATFS = 158 // { int fstatfs(int fd, struct statfs *buf); }
- SYS_UNMOUNT = 159 // { int unmount(user_addr_t path, int flags); }
- // SYS_NOSYS = 160; // { int nosys(void); } { old async_daemon }
- SYS_GETFH = 161 // { int getfh(char *fname, fhandle_t *fhp); }
- // SYS_NOSYS = 161; // { int nosys(void); }
- // SYS_NOSYS = 162; // { int nosys(void); } { old getdomainname }
- // SYS_NOSYS = 163; // { int nosys(void); } { old setdomainname }
- // SYS_NOSYS = 164; // { int nosys(void); }
- SYS_QUOTACTL = 165 // { int quotactl(const char *path, int cmd, int uid, caddr_t arg); }
- // SYS_NOSYS = 166; // { int nosys(void); } { old exportfs }
- SYS_MOUNT = 167 // { int mount(char *type, char *path, int flags, caddr_t data); }
- // SYS_NOSYS = 168; // { int nosys(void); } { old ustat }
- SYS_CSOPS = 169 // { int csops(pid_t pid, uint32_t ops, user_addr_t useraddr, user_size_t usersize); }
- // SYS_NOSYS = 171; // { int nosys(void); } { old wait3 }
- // SYS_NOSYS = 172; // { int nosys(void); } { old rpause }
- SYS_WAITID = 173 // { int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options); }
- // SYS_NOSYS = 174; // { int nosys(void); } { old getdents }
- // SYS_NOSYS = 175; // { int nosys(void); } { old gc_control }
- SYS_ADD_PROFIL = 176 // { int add_profil(short *bufbase, size_t bufsize, u_long pcoffset, u_int pcscale); }
- // SYS_NOSYS = 177; // { int nosys(void); }
- // SYS_NOSYS = 178; // { int nosys(void); }
- // SYS_NOSYS = 179; // { int nosys(void); }
- SYS_KDEBUG_TRACE = 180 // { int kdebug_trace(int code, int arg1, int arg2, int arg3, int arg4, int arg5) NO_SYSCALL_STUB; }
- SYS_SETGID = 181 // { int setgid(gid_t gid); }
- SYS_SETEGID = 182 // { int setegid(gid_t egid); }
- SYS_SETEUID = 183 // { int seteuid(uid_t euid); }
- SYS_SIGRETURN = 184 // { int sigreturn(struct ucontext *uctx, int infostyle); }
- // SYS_NOSYS = 186; // { int nosys(void); }
- // SYS_NOSYS = 187; // { int nosys(void); }
- SYS_STAT = 188 // { int stat(user_addr_t path, user_addr_t ub); }
- SYS_FSTAT = 189 // { int fstat(int fd, user_addr_t ub); }
- SYS_LSTAT = 190 // { int lstat(user_addr_t path, user_addr_t ub); }
- SYS_PATHCONF = 191 // { int pathconf(char *path, int name); }
- SYS_FPATHCONF = 192 // { int fpathconf(int fd, int name); }
- // SYS_NOSYS = 193; // { int nosys(void); }
- SYS_GETRLIMIT = 194 // { int getrlimit(u_int which, struct rlimit *rlp); }
- SYS_SETRLIMIT = 195 // { int setrlimit(u_int which, struct rlimit *rlp); }
- SYS_GETDIRENTRIES = 196 // { int getdirentries(int fd, char *buf, u_int count, long *basep); }
- SYS_MMAP = 197 // { user_addr_t mmap(caddr_t addr, size_t len, int prot, int flags, int fd, off_t pos); }
- // SYS_NOSYS = 198; // { int nosys(void); } { __syscall }
- SYS_LSEEK = 199 // { off_t lseek(int fd, off_t offset, int whence); }
- SYS_TRUNCATE = 200 // { int truncate(char *path, off_t length); }
- SYS_FTRUNCATE = 201 // { int ftruncate(int fd, off_t length); }
- SYS___SYSCTL = 202 // { int __sysctl(int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen); }
- SYS_MLOCK = 203 // { int mlock(caddr_t addr, size_t len); }
- SYS_MUNLOCK = 204 // { int munlock(caddr_t addr, size_t len); }
- SYS_UNDELETE = 205 // { int undelete(user_addr_t path); }
- SYS_ATSOCKET = 206 // { int ATsocket(int proto); }
- // SYS_NOSYS = 213; // { int nosys(void); } { Reserved for AppleTalk }
- // SYS_NOSYS = 206; // { int nosys(void); }
- // SYS_NOSYS = 207; // { int nosys(void); }
- // SYS_NOSYS = 208; // { int nosys(void); }
- // SYS_NOSYS = 209; // { int nosys(void); }
- // SYS_NOSYS = 210; // { int nosys(void); }
- // SYS_NOSYS = 211; // { int nosys(void); }
- // SYS_NOSYS = 212; // { int nosys(void); }
- // SYS_NOSYS = 213; // { int nosys(void); } { Reserved for AppleTalk }
- SYS_KQUEUE_FROM_PORTSET_NP = 214 // { int kqueue_from_portset_np(int portset); }
- SYS_KQUEUE_PORTSET_NP = 215 // { int kqueue_portset_np(int fd); }
- SYS_GETATTRLIST = 220 // { int getattrlist(const char *path, struct attrlist *alist, void *attributeBuffer, size_t bufferSize, u_long options); }
- SYS_SETATTRLIST = 221 // { int setattrlist(const char *path, struct attrlist *alist, void *attributeBuffer, size_t bufferSize, u_long options); }
- SYS_GETDIRENTRIESATTR = 222 // { int getdirentriesattr(int fd, struct attrlist *alist, void *buffer, size_t buffersize, u_long *count, u_long *basep, u_long *newstate, u_long options); }
- SYS_EXCHANGEDATA = 223 // { int exchangedata(const char *path1, const char *path2, u_long options); }
- // SYS_NOSYS = 224; // { int nosys(void); } { was checkuseraccess }
- SYS_SEARCHFS = 225 // { int searchfs(const char *path, struct fssearchblock *searchblock, u_long *nummatches, u_long scriptcode, u_long options, struct searchstate *state); }
- SYS_DELETE = 226 // { int delete(user_addr_t path) NO_SYSCALL_STUB; } { private delete (Carbon semantics) }
- SYS_COPYFILE = 227 // { int copyfile(char *from, char *to, int mode, int flags) NO_SYSCALL_STUB; }
- // SYS_NOSYS = 228; // { int nosys(void); }
- // SYS_NOSYS = 229; // { int nosys(void); }
- SYS_POLL = 230 // { int poll(struct pollfd *fds, u_int nfds, int timeout); }
- SYS_WATCHEVENT = 231 // { int watchevent(struct eventreq *u_req, int u_eventmask); }
- SYS_WAITEVENT = 232 // { int waitevent(struct eventreq *u_req, struct timeval *tv); }
- SYS_MODWATCH = 233 // { int modwatch(struct eventreq *u_req, int u_eventmask); }
- SYS_GETXATTR = 234 // { user_ssize_t getxattr(user_addr_t path, user_addr_t attrname, user_addr_t value, size_t size, uint32_t position, int options); }
- SYS_FGETXATTR = 235 // { user_ssize_t fgetxattr(int fd, user_addr_t attrname, user_addr_t value, size_t size, uint32_t position, int options); }
- SYS_SETXATTR = 236 // { int setxattr(user_addr_t path, user_addr_t attrname, user_addr_t value, size_t size, uint32_t position, int options); }
- SYS_FSETXATTR = 237 // { int fsetxattr(int fd, user_addr_t attrname, user_addr_t value, size_t size, uint32_t position, int options); }
- SYS_REMOVEXATTR = 238 // { int removexattr(user_addr_t path, user_addr_t attrname, int options); }
- SYS_FREMOVEXATTR = 239 // { int fremovexattr(int fd, user_addr_t attrname, int options); }
- SYS_LISTXATTR = 240 // { user_ssize_t listxattr(user_addr_t path, user_addr_t namebuf, size_t bufsize, int options); }
- SYS_FLISTXATTR = 241 // { user_ssize_t flistxattr(int fd, user_addr_t namebuf, size_t bufsize, int options); }
- SYS_FSCTL = 242 // { int fsctl(const char *path, u_long cmd, caddr_t data, u_long options); }
- SYS_INITGROUPS = 243 // { int initgroups(u_int gidsetsize, gid_t *gidset, int gmuid); }
- SYS_POSIX_SPAWN = 244 // { int posix_spawn(pid_t *pid, const char *path, const struct _posix_spawn_args_desc *adesc, char **argv, char **envp); }
- // SYS_NOSYS = 245; // { int nosys(void); }
- // SYS_NOSYS = 246; // { int nosys(void); }
- SYS_NFSCLNT = 247 // { int nfsclnt(int flag, caddr_t argp); }
- // SYS_NOSYS = 247; // { int nosys(void); }
- SYS_FHOPEN = 248 // { int fhopen(const struct fhandle *u_fhp, int flags); }
- // SYS_NOSYS = 248; // { int nosys(void); }
- // SYS_NOSYS = 249; // { int nosys(void); }
- SYS_MINHERIT = 250 // { int minherit(void *addr, size_t len, int inherit); }
- SYS_SEMSYS = 251 // { int semsys(u_int which, int a2, int a3, int a4, int a5); }
- // SYS_NOSYS = 251; // { int nosys(void); }
- SYS_MSGSYS = 252 // { int msgsys(u_int which, int a2, int a3, int a4, int a5); }
- // SYS_NOSYS = 252; // { int nosys(void); }
- SYS_SHMSYS = 253 // { int shmsys(u_int which, int a2, int a3, int a4); }
- // SYS_NOSYS = 253; // { int nosys(void); }
- SYS_SEMCTL = 254 // { int semctl(int semid, int semnum, int cmd, semun_t arg); }
- SYS_SEMGET = 255 // { int semget(key_t key, int nsems, int semflg); }
- SYS_SEMOP = 256 // { int semop(int semid, struct sembuf *sops, int nsops); }
- // SYS_NOSYS = 257; // { int nosys(void); }
- // SYS_NOSYS = 254; // { int nosys(void); }
- // SYS_NOSYS = 255; // { int nosys(void); }
- // SYS_NOSYS = 256; // { int nosys(void); }
- // SYS_NOSYS = 257; // { int nosys(void); }
- SYS_MSGCTL = 258 // { int msgctl(int msqid, int cmd, struct msqid_ds *buf); }
- SYS_MSGGET = 259 // { int msgget(key_t key, int msgflg); }
- SYS_MSGSND = 260 // { int msgsnd(int msqid, void *msgp, size_t msgsz, int msgflg); }
- SYS_MSGRCV = 261 // { user_ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); }
- // SYS_NOSYS = 258; // { int nosys(void); }
- // SYS_NOSYS = 259; // { int nosys(void); }
- // SYS_NOSYS = 260; // { int nosys(void); }
- // SYS_NOSYS = 261; // { int nosys(void); }
- SYS_SHMAT = 262 // { user_addr_t shmat(int shmid, void *shmaddr, int shmflg); }
- SYS_SHMCTL = 263 // { int shmctl(int shmid, int cmd, struct shmid_ds *buf); }
- SYS_SHMDT = 264 // { int shmdt(void *shmaddr); }
- SYS_SHMGET = 265 // { int shmget(key_t key, size_t size, int shmflg); }
- // SYS_NOSYS = 262; // { int nosys(void); }
- // SYS_NOSYS = 263; // { int nosys(void); }
- // SYS_NOSYS = 264; // { int nosys(void); }
- // SYS_NOSYS = 265; // { int nosys(void); }
- SYS_SHM_OPEN = 266 // { int shm_open(const char *name, int oflag, int mode); }
- SYS_SHM_UNLINK = 267 // { int shm_unlink(const char *name); }
- SYS_SEM_OPEN = 268 // { user_addr_t sem_open(const char *name, int oflag, int mode, int value); }
- SYS_SEM_CLOSE = 269 // { int sem_close(sem_t *sem); }
- SYS_SEM_UNLINK = 270 // { int sem_unlink(const char *name); }
- SYS_SEM_WAIT = 271 // { int sem_wait(sem_t *sem); }
- SYS_SEM_TRYWAIT = 272 // { int sem_trywait(sem_t *sem); }
- SYS_SEM_POST = 273 // { int sem_post(sem_t *sem); }
- SYS_SEM_GETVALUE = 274 // { int sem_getvalue(sem_t *sem, int *sval); }
- SYS_SEM_INIT = 275 // { int sem_init(sem_t *sem, int phsared, u_int value); }
- SYS_SEM_DESTROY = 276 // { int sem_destroy(sem_t *sem); }
- SYS_OPEN_EXTENDED = 277 // { int open_extended(user_addr_t path, int flags, uid_t uid, gid_t gid, int mode, user_addr_t xsecurity) NO_SYSCALL_STUB; }
- SYS_UMASK_EXTENDED = 278 // { int umask_extended(int newmask, user_addr_t xsecurity) NO_SYSCALL_STUB; }
- SYS_STAT_EXTENDED = 279 // { int stat_extended(user_addr_t path, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; }
- SYS_LSTAT_EXTENDED = 280 // { int lstat_extended(user_addr_t path, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; }
- SYS_FSTAT_EXTENDED = 281 // { int fstat_extended(int fd, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; }
- SYS_CHMOD_EXTENDED = 282 // { int chmod_extended(user_addr_t path, uid_t uid, gid_t gid, int mode, user_addr_t xsecurity) NO_SYSCALL_STUB; }
- SYS_FCHMOD_EXTENDED = 283 // { int fchmod_extended(int fd, uid_t uid, gid_t gid, int mode, user_addr_t xsecurity) NO_SYSCALL_STUB; }
- SYS_ACCESS_EXTENDED = 284 // { int access_extended(user_addr_t entries, size_t size, user_addr_t results, uid_t uid) NO_SYSCALL_STUB; }
- SYS_SETTID = 285 // { int settid(uid_t uid, gid_t gid) NO_SYSCALL_STUB; }
- SYS_GETTID = 286 // { int gettid(uid_t *uidp, gid_t *gidp) NO_SYSCALL_STUB; }
- SYS_SETSGROUPS = 287 // { int setsgroups(int setlen, user_addr_t guidset) NO_SYSCALL_STUB; }
- SYS_GETSGROUPS = 288 // { int getsgroups(user_addr_t setlen, user_addr_t guidset) NO_SYSCALL_STUB; }
- SYS_SETWGROUPS = 289 // { int setwgroups(int setlen, user_addr_t guidset) NO_SYSCALL_STUB; }
- SYS_GETWGROUPS = 290 // { int getwgroups(user_addr_t setlen, user_addr_t guidset) NO_SYSCALL_STUB; }
- SYS_MKFIFO_EXTENDED = 291 // { int mkfifo_extended(user_addr_t path, uid_t uid, gid_t gid, int mode, user_addr_t xsecurity) NO_SYSCALL_STUB; }
- SYS_MKDIR_EXTENDED = 292 // { int mkdir_extended(user_addr_t path, uid_t uid, gid_t gid, int mode, user_addr_t xsecurity) NO_SYSCALL_STUB; }
- SYS_IDENTITYSVC = 293 // { int identitysvc(int opcode, user_addr_t message) NO_SYSCALL_STUB; }
- SYS_SHARED_REGION_CHECK_NP = 294 // { int shared_region_check_np(uint64_t *start_address) NO_SYSCALL_STUB; }
- SYS_SHARED_REGION_MAP_NP = 295 // { int shared_region_map_np(int fd, uint32_t count, const struct shared_file_mapping_np *mappings) NO_SYSCALL_STUB; }
- // SYS_NOSYS = 296; // { int nosys(void); } { old load_shared_file }
- // SYS_NOSYS = 297; // { int nosys(void); } { old reset_shared_file }
- // SYS_NOSYS = 298; // { int nosys(void); } { old new_system_shared_regions }
- // SYS_ENOSYS = 299; // { int enosys(void); } { old shared_region_map_file_np }
- // SYS_ENOSYS = 300; // { int enosys(void); } { old shared_region_make_private_np }
- SYS___PTHREAD_MUTEX_DESTROY = 301 // { int __pthread_mutex_destroy(int mutexid); }
- SYS___PTHREAD_MUTEX_INIT = 302 // { int __pthread_mutex_init(user_addr_t mutex, user_addr_t attr); }
- SYS___PTHREAD_MUTEX_LOCK = 303 // { int __pthread_mutex_lock(int mutexid); }
- SYS___PTHREAD_MUTEX_TRYLOCK = 304 // { int __pthread_mutex_trylock(int mutexid); }
- SYS___PTHREAD_MUTEX_UNLOCK = 305 // { int __pthread_mutex_unlock(int mutexid); }
- SYS___PTHREAD_COND_INIT = 306 // { int __pthread_cond_init(user_addr_t cond, user_addr_t attr); }
- SYS___PTHREAD_COND_DESTROY = 307 // { int __pthread_cond_destroy(int condid); }
- SYS___PTHREAD_COND_BROADCAST = 308 // { int __pthread_cond_broadcast(int condid); }
- SYS___PTHREAD_COND_SIGNAL = 309 // { int __pthread_cond_signal(int condid); }
- SYS_GETSID = 310 // { int getsid(pid_t pid); }
- SYS_SETTID_WITH_PID = 311 // { int settid_with_pid(pid_t pid, int assume) NO_SYSCALL_STUB; }
- SYS___PTHREAD_COND_TIMEDWAIT = 312 // { int __pthread_cond_timedwait(int condid, int mutexid, user_addr_t abstime); }
- SYS_AIO_FSYNC = 313 // { int aio_fsync(int op, user_addr_t aiocbp); }
- SYS_AIO_RETURN = 314 // { user_ssize_t aio_return(user_addr_t aiocbp); }
- SYS_AIO_SUSPEND = 315 // { int aio_suspend(user_addr_t aiocblist, int nent, user_addr_t timeoutp); }
- SYS_AIO_CANCEL = 316 // { int aio_cancel(int fd, user_addr_t aiocbp); }
- SYS_AIO_ERROR = 317 // { int aio_error(user_addr_t aiocbp); }
- SYS_AIO_READ = 318 // { int aio_read(user_addr_t aiocbp); }
- SYS_AIO_WRITE = 319 // { int aio_write(user_addr_t aiocbp); }
- SYS_LIO_LISTIO = 320 // { int lio_listio(int mode, user_addr_t aiocblist, int nent, user_addr_t sigp); }
- SYS___PTHREAD_COND_WAIT = 321 // { int __pthread_cond_wait(int condid, int mutexid); }
- SYS_IOPOLICYSYS = 322 // { int iopolicysys(int cmd, void *arg) NO_SYSCALL_STUB; }
- // SYS_NOSYS = 323; // { int nosys(void); }
- SYS_MLOCKALL = 324 // { int mlockall(int how); }
- SYS_MUNLOCKALL = 325 // { int munlockall(int how); }
- // SYS_NOSYS = 326; // { int nosys(void); }
- SYS_ISSETUGID = 327 // { int issetugid(void); }
- SYS___PTHREAD_KILL = 328 // { int __pthread_kill(int thread_port, int sig); }
- SYS___PTHREAD_SIGMASK = 329 // { int __pthread_sigmask(int how, user_addr_t set, user_addr_t oset); }
- SYS___SIGWAIT = 330 // { int __sigwait(user_addr_t set, user_addr_t sig); }
- SYS___DISABLE_THREADSIGNAL = 331 // { int __disable_threadsignal(int value); }
- SYS___PTHREAD_MARKCANCEL = 332 // { int __pthread_markcancel(int thread_port); }
- SYS___PTHREAD_CANCELED = 333 // { int __pthread_canceled(int action); }
- SYS___SEMWAIT_SIGNAL = 334 // { int __semwait_signal(int cond_sem, int mutex_sem, int timeout, int relative, time_t tv_sec, int32_t tv_nsec); }
- // SYS_NOSYS = 335; // { int nosys(void); } { old utrace }
- SYS_PROC_INFO = 336 // { int proc_info(int32_t callnum,int32_t pid,uint32_t flavor, uint64_t arg,user_addr_t buffer,int32_t buffersize) NO_SYSCALL_STUB; }
- SYS_SENDFILE = 337 // { int sendfile(int fd, int s, off_t offset, off_t *nbytes, struct sf_hdtr *hdtr, int flags); }
- // SYS_NOSYS = 337; // { int nosys(void); }
- SYS_STAT64 = 338 // { int stat64(user_addr_t path, user_addr_t ub); }
- SYS_FSTAT64 = 339 // { int fstat64(int fd, user_addr_t ub); }
- SYS_LSTAT64 = 340 // { int lstat64(user_addr_t path, user_addr_t ub); }
- SYS_STAT64_EXTENDED = 341 // { int stat64_extended(user_addr_t path, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; }
- SYS_LSTAT64_EXTENDED = 342 // { int lstat64_extended(user_addr_t path, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; }
- SYS_FSTAT64_EXTENDED = 343 // { int fstat64_extended(int fd, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; }
- SYS_GETDIRENTRIES64 = 344 // { user_ssize_t getdirentries64(int fd, void *buf, user_size_t bufsize, off_t *position) NO_SYSCALL_STUB; }
- SYS_STATFS64 = 345 // { int statfs64(char *path, struct statfs64 *buf); }
- SYS_FSTATFS64 = 346 // { int fstatfs64(int fd, struct statfs64 *buf); }
- SYS_GETFSSTAT64 = 347 // { int getfsstat64(user_addr_t buf, int bufsize, int flags); }
- SYS___PTHREAD_CHDIR = 348 // { int __pthread_chdir(user_addr_t path); }
- SYS___PTHREAD_FCHDIR = 349 // { int __pthread_fchdir(int fd); }
- SYS_AUDIT = 350 // { int audit(void *record, int length); }
- SYS_AUDITON = 351 // { int auditon(int cmd, void *data, int length); }
- // SYS_NOSYS = 352; // { int nosys(void); }
- SYS_GETAUID = 353 // { int getauid(au_id_t *auid); }
- SYS_SETAUID = 354 // { int setauid(au_id_t *auid); }
- SYS_GETAUDIT = 355 // { int getaudit(struct auditinfo *auditinfo); }
- SYS_SETAUDIT = 356 // { int setaudit(struct auditinfo *auditinfo); }
- SYS_GETAUDIT_ADDR = 357 // { int getaudit_addr(struct auditinfo_addr *auditinfo_addr, int length); }
- SYS_SETAUDIT_ADDR = 358 // { int setaudit_addr(struct auditinfo_addr *auditinfo_addr, int length); }
- SYS_AUDITCTL = 359 // { int auditctl(char *path); }
- // SYS_NOSYS = 350; // { int nosys(void); }
- // SYS_NOSYS = 351; // { int nosys(void); }
- // SYS_NOSYS = 352; // { int nosys(void); }
- // SYS_NOSYS = 353; // { int nosys(void); }
- // SYS_NOSYS = 354; // { int nosys(void); }
- // SYS_NOSYS = 355; // { int nosys(void); }
- // SYS_NOSYS = 356; // { int nosys(void); }
- // SYS_NOSYS = 357; // { int nosys(void); }
- // SYS_NOSYS = 358; // { int nosys(void); }
- // SYS_NOSYS = 359; // { int nosys(void); }
- SYS_BSDTHREAD_CREATE = 360 // { user_addr_t bsdthread_create(user_addr_t func, user_addr_t func_arg, user_addr_t stack, user_addr_t pthread, uint32_t flags) NO_SYSCALL_STUB; }
- SYS_BSDTHREAD_TERMINATE = 361 // { int bsdthread_terminate(user_addr_t stackaddr, size_t freesize, uint32_t port, uint32_t sem) NO_SYSCALL_STUB; }
- SYS_KQUEUE = 362 // { int kqueue(void); }
- SYS_KEVENT = 363 // { int kevent(int fd, const struct kevent *changelist, int nchanges, struct kevent *eventlist, int nevents, const struct timespec *timeout); }
- SYS_LCHOWN = 364 // { int lchown(user_addr_t path, uid_t owner, gid_t group); }
- SYS_STACK_SNAPSHOT = 365 // { int stack_snapshot(pid_t pid, user_addr_t tracebuf, uint32_t tracebuf_size, uint32_t options) NO_SYSCALL_STUB; }
- SYS_BSDTHREAD_REGISTER = 366 // { int bsdthread_register(user_addr_t threadstart, user_addr_t wqthread, int pthsize) NO_SYSCALL_STUB; }
- SYS_WORKQ_OPEN = 367 // { int workq_open(void) NO_SYSCALL_STUB; }
- SYS_WORKQ_OPS = 368 // { int workq_ops(int options, user_addr_t item, int prio) NO_SYSCALL_STUB; }
- // SYS_NOSYS = 369; // { int nosys(void); }
- // SYS_NOSYS = 370; // { int nosys(void); }
- // SYS_NOSYS = 371; // { int nosys(void); }
- // SYS_NOSYS = 372; // { int nosys(void); }
- // SYS_NOSYS = 373; // { int nosys(void); }
- // SYS_NOSYS = 374; // { int nosys(void); }
- // SYS_NOSYS = 375; // { int nosys(void); }
- // SYS_NOSYS = 376; // { int nosys(void); }
- // SYS_NOSYS = 377; // { int nosys(void); }
- // SYS_NOSYS = 378; // { int nosys(void); }
- // SYS_NOSYS = 379; // { int nosys(void); }
- SYS___MAC_EXECVE = 380 // { int __mac_execve(char *fname, char **argp, char **envp, struct mac *mac_p); }
- SYS___MAC_SYSCALL = 381 // { int __mac_syscall(char *policy, int call, user_addr_t arg); }
- SYS___MAC_GET_FILE = 382 // { int __mac_get_file(char *path_p, struct mac *mac_p); }
- SYS___MAC_SET_FILE = 383 // { int __mac_set_file(char *path_p, struct mac *mac_p); }
- SYS___MAC_GET_LINK = 384 // { int __mac_get_link(char *path_p, struct mac *mac_p); }
- SYS___MAC_SET_LINK = 385 // { int __mac_set_link(char *path_p, struct mac *mac_p); }
- SYS___MAC_GET_PROC = 386 // { int __mac_get_proc(struct mac *mac_p); }
- SYS___MAC_SET_PROC = 387 // { int __mac_set_proc(struct mac *mac_p); }
- SYS___MAC_GET_FD = 388 // { int __mac_get_fd(int fd, struct mac *mac_p); }
- SYS___MAC_SET_FD = 389 // { int __mac_set_fd(int fd, struct mac *mac_p); }
- SYS___MAC_GET_PID = 390 // { int __mac_get_pid(pid_t pid, struct mac *mac_p); }
- SYS___MAC_GET_LCID = 391 // { int __mac_get_lcid(pid_t lcid, struct mac *mac_p); }
- SYS___MAC_GET_LCTX = 392 // { int __mac_get_lctx(struct mac *mac_p); }
- SYS___MAC_SET_LCTX = 393 // { int __mac_set_lctx(struct mac *mac_p); }
- SYS_SETLCID = 394 // { int setlcid(pid_t pid, pid_t lcid) NO_SYSCALL_STUB; }
- SYS_GETLCID = 395 // { int getlcid(pid_t pid) NO_SYSCALL_STUB; }
- SYS_READ_NOCANCEL = 396 // { user_ssize_t read_nocancel(int fd, user_addr_t cbuf, user_size_t nbyte) NO_SYSCALL_STUB; }
- SYS_WRITE_NOCANCEL = 397 // { user_ssize_t write_nocancel(int fd, user_addr_t cbuf, user_size_t nbyte) NO_SYSCALL_STUB; }
- SYS_OPEN_NOCANCEL = 398 // { int open_nocancel(user_addr_t path, int flags, int mode) NO_SYSCALL_STUB; }
- SYS_CLOSE_NOCANCEL = 399 // { int close_nocancel(int fd) NO_SYSCALL_STUB; }
- SYS_WAIT4_NOCANCEL = 400 // { int wait4_nocancel(int pid, user_addr_t status, int options, user_addr_t rusage) NO_SYSCALL_STUB; }
- SYS_RECVMSG_NOCANCEL = 401 // { int recvmsg_nocancel(int s, struct msghdr *msg, int flags) NO_SYSCALL_STUB; }
- SYS_SENDMSG_NOCANCEL = 402 // { int sendmsg_nocancel(int s, caddr_t msg, int flags) NO_SYSCALL_STUB; }
- SYS_RECVFROM_NOCANCEL = 403 // { int recvfrom_nocancel(int s, void *buf, size_t len, int flags, struct sockaddr *from, int *fromlenaddr) NO_SYSCALL_STUB; }
- SYS_ACCEPT_NOCANCEL = 404 // { int accept_nocancel(int s, caddr_t name, socklen_t *anamelen) NO_SYSCALL_STUB; }
- // SYS_NOSYS = 401; // { int nosys(void); }
- // SYS_NOSYS = 402; // { int nosys(void); }
- // SYS_NOSYS = 403; // { int nosys(void); }
- // SYS_NOSYS = 404; // { int nosys(void); }
- SYS_MSYNC_NOCANCEL = 405 // { int msync_nocancel(caddr_t addr, size_t len, int flags) NO_SYSCALL_STUB; }
- SYS_FCNTL_NOCANCEL = 406 // { int fcntl_nocancel(int fd, int cmd, long arg) NO_SYSCALL_STUB; }
- SYS_SELECT_NOCANCEL = 407 // { int select_nocancel(int nd, u_int32_t *in, u_int32_t *ou, u_int32_t *ex, struct timeval *tv) NO_SYSCALL_STUB; }
- SYS_FSYNC_NOCANCEL = 408 // { int fsync_nocancel(int fd) NO_SYSCALL_STUB; }
- SYS_CONNECT_NOCANCEL = 409 // { int connect_nocancel(int s, caddr_t name, socklen_t namelen) NO_SYSCALL_STUB; }
- // SYS_NOSYS = 409; // { int nosys(void); }
- SYS_SIGSUSPEND_NOCANCEL = 410 // { int sigsuspend_nocancel(sigset_t mask) NO_SYSCALL_STUB; }
- SYS_READV_NOCANCEL = 411 // { user_ssize_t readv_nocancel(int fd, struct iovec *iovp, u_int iovcnt) NO_SYSCALL_STUB; }
- SYS_WRITEV_NOCANCEL = 412 // { user_ssize_t writev_nocancel(int fd, struct iovec *iovp, u_int iovcnt) NO_SYSCALL_STUB; }
- SYS_SENDTO_NOCANCEL = 413 // { int sendto_nocancel(int s, caddr_t buf, size_t len, int flags, caddr_t to, socklen_t tolen) NO_SYSCALL_STUB; }
- // SYS_NOSYS = 413; // { int nosys(void); }
- SYS_PREAD_NOCANCEL = 414 // { user_ssize_t pread_nocancel(int fd, user_addr_t buf, user_size_t nbyte, off_t offset) NO_SYSCALL_STUB; }
- SYS_PWRITE_NOCANCEL = 415 // { user_ssize_t pwrite_nocancel(int fd, user_addr_t buf, user_size_t nbyte, off_t offset) NO_SYSCALL_STUB; }
- SYS_WAITID_NOCANCEL = 416 // { int waitid_nocancel(idtype_t idtype, id_t id, siginfo_t *infop, int options) NO_SYSCALL_STUB; }
- SYS_POLL_NOCANCEL = 417 // { int poll_nocancel(struct pollfd *fds, u_int nfds, int timeout) NO_SYSCALL_STUB; }
- SYS_MSGSND_NOCANCEL = 418 // { int msgsnd_nocancel(int msqid, void *msgp, size_t msgsz, int msgflg) NO_SYSCALL_STUB; }
- SYS_MSGRCV_NOCANCEL = 419 // { user_ssize_t msgrcv_nocancel(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg) NO_SYSCALL_STUB; }
- // SYS_NOSYS = 418; // { int nosys(void); }
- // SYS_NOSYS = 419; // { int nosys(void); }
- SYS_SEM_WAIT_NOCANCEL = 420 // { int sem_wait_nocancel(sem_t *sem) NO_SYSCALL_STUB; }
- SYS_AIO_SUSPEND_NOCANCEL = 421 // { int aio_suspend_nocancel(user_addr_t aiocblist, int nent, user_addr_t timeoutp) NO_SYSCALL_STUB; }
- SYS___SIGWAIT_NOCANCEL = 422 // { int __sigwait_nocancel(user_addr_t set, user_addr_t sig) NO_SYSCALL_STUB; }
- SYS___SEMWAIT_SIGNAL_NOCANCEL = 423 // { int __semwait_signal_nocancel(int cond_sem, int mutex_sem, int timeout, int relative, time_t tv_sec, int32_t tv_nsec) NO_SYSCALL_STUB; }
- SYS___MAC_MOUNT = 424 // { int __mac_mount(char *type, char *path, int flags, caddr_t data, struct mac *mac_p); }
- SYS___MAC_GET_MOUNT = 425 // { int __mac_get_mount(char *path, struct mac *mac_p); }
- SYS___MAC_GETFSSTAT = 426 // { int __mac_getfsstat(user_addr_t buf, int bufsize, user_addr_t mac, int macsize, int flags); }
+ SYS_SYSCALL = 0
+ SYS_EXIT = 1
+ SYS_FORK = 2
+ SYS_READ = 3
+ SYS_WRITE = 4
+ SYS_OPEN = 5
+ SYS_CLOSE = 6
+ SYS_WAIT4 = 7
+ SYS_LINK = 9
+ SYS_UNLINK = 10
+ SYS_CHDIR = 12
+ SYS_FCHDIR = 13
+ SYS_MKNOD = 14
+ SYS_CHMOD = 15
+ SYS_CHOWN = 16
+ SYS_GETFSSTAT = 18
+ SYS_GETPID = 20
+ SYS_SETUID = 23
+ SYS_GETUID = 24
+ SYS_GETEUID = 25
+ SYS_PTRACE = 26
+ SYS_RECVMSG = 27
+ SYS_SENDMSG = 28
+ SYS_RECVFROM = 29
+ SYS_ACCEPT = 30
+ SYS_GETPEERNAME = 31
+ SYS_GETSOCKNAME = 32
+ SYS_ACCESS = 33
+ SYS_CHFLAGS = 34
+ SYS_FCHFLAGS = 35
+ SYS_SYNC = 36
+ SYS_KILL = 37
+ SYS_GETPPID = 39
+ SYS_DUP = 41
+ SYS_PIPE = 42
+ SYS_GETEGID = 43
+ SYS_PROFIL = 44
+ SYS_SIGACTION = 46
+ SYS_GETGID = 47
+ SYS_SIGPROCMASK = 48
+ SYS_GETLOGIN = 49
+ SYS_SETLOGIN = 50
+ SYS_ACCT = 51
+ SYS_SIGPENDING = 52
+ SYS_SIGALTSTACK = 53
+ SYS_IOCTL = 54
+ SYS_REBOOT = 55
+ SYS_REVOKE = 56
+ SYS_SYMLINK = 57
+ SYS_READLINK = 58
+ SYS_EXECVE = 59
+ SYS_UMASK = 60
+ SYS_CHROOT = 61
+ SYS_MSYNC = 65
+ SYS_VFORK = 66
+ SYS_MUNMAP = 73
+ SYS_MPROTECT = 74
+ SYS_MADVISE = 75
+ SYS_MINCORE = 78
+ SYS_GETGROUPS = 79
+ SYS_SETGROUPS = 80
+ SYS_GETPGRP = 81
+ SYS_SETPGID = 82
+ SYS_SETITIMER = 83
+ SYS_SWAPON = 85
+ SYS_GETITIMER = 86
+ SYS_GETDTABLESIZE = 89
+ SYS_DUP2 = 90
+ SYS_FCNTL = 92
+ SYS_SELECT = 93
+ SYS_FSYNC = 95
+ SYS_SETPRIORITY = 96
+ SYS_SOCKET = 97
+ SYS_CONNECT = 98
+ SYS_GETPRIORITY = 100
+ SYS_BIND = 104
+ SYS_SETSOCKOPT = 105
+ SYS_LISTEN = 106
+ SYS_SIGSUSPEND = 111
+ SYS_GETTIMEOFDAY = 116
+ SYS_GETRUSAGE = 117
+ SYS_GETSOCKOPT = 118
+ SYS_READV = 120
+ SYS_WRITEV = 121
+ SYS_SETTIMEOFDAY = 122
+ SYS_FCHOWN = 123
+ SYS_FCHMOD = 124
+ SYS_SETREUID = 126
+ SYS_SETREGID = 127
+ SYS_RENAME = 128
+ SYS_FLOCK = 131
+ SYS_MKFIFO = 132
+ SYS_SENDTO = 133
+ SYS_SHUTDOWN = 134
+ SYS_SOCKETPAIR = 135
+ SYS_MKDIR = 136
+ SYS_RMDIR = 137
+ SYS_UTIMES = 138
+ SYS_FUTIMES = 139
+ SYS_ADJTIME = 140
+ SYS_GETHOSTUUID = 142
+ SYS_SETSID = 147
+ SYS_GETPGID = 151
+ SYS_SETPRIVEXEC = 152
+ SYS_PREAD = 153
+ SYS_PWRITE = 154
+ SYS_NFSSVC = 155
+ SYS_STATFS = 157
+ SYS_FSTATFS = 158
+ SYS_UNMOUNT = 159
+ SYS_GETFH = 161
+ SYS_QUOTACTL = 165
+ SYS_MOUNT = 167
+ SYS_CSOPS = 169
+ SYS_WAITID = 173
+ SYS_ADD_PROFIL = 176
+ SYS_KDEBUG_TRACE = 180
+ SYS_SETGID = 181
+ SYS_SETEGID = 182
+ SYS_SETEUID = 183
+ SYS_SIGRETURN = 184
+ SYS_CHUD = 185
+ SYS_FDATASYNC = 187
+ SYS_STAT = 188
+ SYS_FSTAT = 189
+ SYS_LSTAT = 190
+ SYS_PATHCONF = 191
+ SYS_FPATHCONF = 192
+ SYS_GETRLIMIT = 194
+ SYS_SETRLIMIT = 195
+ SYS_GETDIRENTRIES = 196
+ SYS_MMAP = 197
+ SYS_LSEEK = 199
+ SYS_TRUNCATE = 200
+ SYS_FTRUNCATE = 201
+ SYS___SYSCTL = 202
+ SYS_MLOCK = 203
+ SYS_MUNLOCK = 204
+ SYS_UNDELETE = 205
+ SYS_ATSOCKET = 206
+ SYS_ATGETMSG = 207
+ SYS_ATPUTMSG = 208
+ SYS_ATPSNDREQ = 209
+ SYS_ATPSNDRSP = 210
+ SYS_ATPGETREQ = 211
+ SYS_ATPGETRSP = 212
+ SYS_MKCOMPLEX = 216
+ SYS_STATV = 217
+ SYS_LSTATV = 218
+ SYS_FSTATV = 219
+ SYS_GETATTRLIST = 220
+ SYS_SETATTRLIST = 221
+ SYS_GETDIRENTRIESATTR = 222
+ SYS_EXCHANGEDATA = 223
+ SYS_SEARCHFS = 225
+ SYS_DELETE = 226
+ SYS_COPYFILE = 227
+ SYS_FGETATTRLIST = 228
+ SYS_FSETATTRLIST = 229
+ SYS_POLL = 230
+ SYS_WATCHEVENT = 231
+ SYS_WAITEVENT = 232
+ SYS_MODWATCH = 233
+ SYS_GETXATTR = 234
+ SYS_FGETXATTR = 235
+ SYS_SETXATTR = 236
+ SYS_FSETXATTR = 237
+ SYS_REMOVEXATTR = 238
+ SYS_FREMOVEXATTR = 239
+ SYS_LISTXATTR = 240
+ SYS_FLISTXATTR = 241
+ SYS_FSCTL = 242
+ SYS_INITGROUPS = 243
+ SYS_POSIX_SPAWN = 244
+ SYS_FFSCTL = 245
+ SYS_NFSCLNT = 247
+ SYS_FHOPEN = 248
+ SYS_MINHERIT = 250
+ SYS_SEMSYS = 251
+ SYS_MSGSYS = 252
+ SYS_SHMSYS = 253
+ SYS_SEMCTL = 254
+ SYS_SEMGET = 255
+ SYS_SEMOP = 256
+ SYS_MSGCTL = 258
+ SYS_MSGGET = 259
+ SYS_MSGSND = 260
+ SYS_MSGRCV = 261
+ SYS_SHMAT = 262
+ SYS_SHMCTL = 263
+ SYS_SHMDT = 264
+ SYS_SHMGET = 265
+ SYS_SHM_OPEN = 266
+ SYS_SHM_UNLINK = 267
+ SYS_SEM_OPEN = 268
+ SYS_SEM_CLOSE = 269
+ SYS_SEM_UNLINK = 270
+ SYS_SEM_WAIT = 271
+ SYS_SEM_TRYWAIT = 272
+ SYS_SEM_POST = 273
+ SYS_SEM_GETVALUE = 274
+ SYS_SEM_INIT = 275
+ SYS_SEM_DESTROY = 276
+ SYS_OPEN_EXTENDED = 277
+ SYS_UMASK_EXTENDED = 278
+ SYS_STAT_EXTENDED = 279
+ SYS_LSTAT_EXTENDED = 280
+ SYS_FSTAT_EXTENDED = 281
+ SYS_CHMOD_EXTENDED = 282
+ SYS_FCHMOD_EXTENDED = 283
+ SYS_ACCESS_EXTENDED = 284
+ SYS_SETTID = 285
+ SYS_GETTID = 286
+ SYS_SETSGROUPS = 287
+ SYS_GETSGROUPS = 288
+ SYS_SETWGROUPS = 289
+ SYS_GETWGROUPS = 290
+ SYS_MKFIFO_EXTENDED = 291
+ SYS_MKDIR_EXTENDED = 292
+ SYS_IDENTITYSVC = 293
+ SYS_SHARED_REGION_CHECK_NP = 294
+ SYS_SHARED_REGION_MAP_NP = 295
+ SYS_VM_PRESSURE_MONITOR = 296
+ SYS_PSYNCH_RW_LONGRDLOCK = 297
+ SYS_PSYNCH_RW_YIELDWRLOCK = 298
+ SYS_PSYNCH_RW_DOWNGRADE = 299
+ SYS_PSYNCH_RW_UPGRADE = 300
+ SYS_PSYNCH_MUTEXWAIT = 301
+ SYS_PSYNCH_MUTEXDROP = 302
+ SYS_PSYNCH_CVBROAD = 303
+ SYS_PSYNCH_CVSIGNAL = 304
+ SYS_PSYNCH_CVWAIT = 305
+ SYS_PSYNCH_RW_RDLOCK = 306
+ SYS_PSYNCH_RW_WRLOCK = 307
+ SYS_PSYNCH_RW_UNLOCK = 308
+ SYS_PSYNCH_RW_UNLOCK2 = 309
+ SYS_GETSID = 310
+ SYS_SETTID_WITH_PID = 311
+ SYS_AIO_FSYNC = 313
+ SYS_AIO_RETURN = 314
+ SYS_AIO_SUSPEND = 315
+ SYS_AIO_CANCEL = 316
+ SYS_AIO_ERROR = 317
+ SYS_AIO_READ = 318
+ SYS_AIO_WRITE = 319
+ SYS_LIO_LISTIO = 320
+ SYS_IOPOLICYSYS = 322
+ SYS_MLOCKALL = 324
+ SYS_MUNLOCKALL = 325
+ SYS_ISSETUGID = 327
+ SYS___PTHREAD_KILL = 328
+ SYS___PTHREAD_SIGMASK = 329
+ SYS___SIGWAIT = 330
+ SYS___DISABLE_THREADSIGNAL = 331
+ SYS___PTHREAD_MARKCANCEL = 332
+ SYS___PTHREAD_CANCELED = 333
+ SYS___SEMWAIT_SIGNAL = 334
+ SYS_PROC_INFO = 336
+ SYS_SENDFILE = 337
+ SYS_STAT64 = 338
+ SYS_FSTAT64 = 339
+ SYS_LSTAT64 = 340
+ SYS_STAT64_EXTENDED = 341
+ SYS_LSTAT64_EXTENDED = 342
+ SYS_FSTAT64_EXTENDED = 343
+ SYS_GETDIRENTRIES64 = 344
+ SYS_STATFS64 = 345
+ SYS_FSTATFS64 = 346
+ SYS_GETFSSTAT64 = 347
+ SYS___PTHREAD_CHDIR = 348
+ SYS___PTHREAD_FCHDIR = 349
+ SYS_AUDIT = 350
+ SYS_AUDITON = 351
+ SYS_GETAUID = 353
+ SYS_SETAUID = 354
+ SYS_GETAUDIT = 355
+ SYS_SETAUDIT = 356
+ SYS_GETAUDIT_ADDR = 357
+ SYS_SETAUDIT_ADDR = 358
+ SYS_AUDITCTL = 359
+ SYS_BSDTHREAD_CREATE = 360
+ SYS_BSDTHREAD_TERMINATE = 361
+ SYS_KQUEUE = 362
+ SYS_KEVENT = 363
+ SYS_LCHOWN = 364
+ SYS_STACK_SNAPSHOT = 365
+ SYS_BSDTHREAD_REGISTER = 366
+ SYS_WORKQ_OPEN = 367
+ SYS_WORKQ_KERNRETURN = 368
+ SYS_KEVENT64 = 369
+ SYS___OLD_SEMWAIT_SIGNAL = 370
+ SYS___OLD_SEMWAIT_SIGNAL_NOCANCEL = 371
+ SYS_THREAD_SELFID = 372
+ SYS___MAC_EXECVE = 380
+ SYS___MAC_SYSCALL = 381
+ SYS___MAC_GET_FILE = 382
+ SYS___MAC_SET_FILE = 383
+ SYS___MAC_GET_LINK = 384
+ SYS___MAC_SET_LINK = 385
+ SYS___MAC_GET_PROC = 386
+ SYS___MAC_SET_PROC = 387
+ SYS___MAC_GET_FD = 388
+ SYS___MAC_SET_FD = 389
+ SYS___MAC_GET_PID = 390
+ SYS___MAC_GET_LCID = 391
+ SYS___MAC_GET_LCTX = 392
+ SYS___MAC_SET_LCTX = 393
+ SYS_SETLCID = 394
+ SYS_GETLCID = 395
+ SYS_READ_NOCANCEL = 396
+ SYS_WRITE_NOCANCEL = 397
+ SYS_OPEN_NOCANCEL = 398
+ SYS_CLOSE_NOCANCEL = 399
+ SYS_WAIT4_NOCANCEL = 400
+ SYS_RECVMSG_NOCANCEL = 401
+ SYS_SENDMSG_NOCANCEL = 402
+ SYS_RECVFROM_NOCANCEL = 403
+ SYS_ACCEPT_NOCANCEL = 404
+ SYS_MSYNC_NOCANCEL = 405
+ SYS_FCNTL_NOCANCEL = 406
+ SYS_SELECT_NOCANCEL = 407
+ SYS_FSYNC_NOCANCEL = 408
+ SYS_CONNECT_NOCANCEL = 409
+ SYS_SIGSUSPEND_NOCANCEL = 410
+ SYS_READV_NOCANCEL = 411
+ SYS_WRITEV_NOCANCEL = 412
+ SYS_SENDTO_NOCANCEL = 413
+ SYS_PREAD_NOCANCEL = 414
+ SYS_PWRITE_NOCANCEL = 415
+ SYS_WAITID_NOCANCEL = 416
+ SYS_POLL_NOCANCEL = 417
+ SYS_MSGSND_NOCANCEL = 418
+ SYS_MSGRCV_NOCANCEL = 419
+ SYS_SEM_WAIT_NOCANCEL = 420
+ SYS_AIO_SUSPEND_NOCANCEL = 421
+ SYS___SIGWAIT_NOCANCEL = 422
+ SYS___SEMWAIT_SIGNAL_NOCANCEL = 423
+ SYS___MAC_MOUNT = 424
+ SYS___MAC_GET_MOUNT = 425
+ SYS___MAC_GETFSSTAT = 426
+ SYS_FSGETPATH = 427
+ SYS_AUDIT_SESSION_SELF = 428
+ SYS_AUDIT_SESSION_JOIN = 429
+ SYS_PID_SUSPEND = 430
+ SYS_PID_RESUME = 431
+ SYS_FILEPORT_MAKEPORT = 432
+ SYS_FILEPORT_MAKEFD = 433
+ SYS_MAXSYSCALL = 434
)
diff --git a/src/pkg/syscall/zsysnum_darwin_amd64.go b/src/pkg/syscall/zsysnum_darwin_amd64.go
index f9c6e077d..50aec39f1 100644
--- a/src/pkg/syscall/zsysnum_darwin_amd64.go
+++ b/src/pkg/syscall/zsysnum_darwin_amd64.go
@@ -1,485 +1,355 @@
-// mksysnum_darwin.pl /home/rsc/pub/xnu-1228/bsd/kern/syscalls.master
+// mksysnum_darwin.pl /usr/include/sys/syscall.h
// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
package syscall
const (
- // SYS_NOSYS = 0; // { int nosys(void); } { indirect syscall }
- SYS_EXIT = 1 // { void exit(int rval); }
- SYS_FORK = 2 // { int fork(void); }
- SYS_READ = 3 // { user_ssize_t read(int fd, user_addr_t cbuf, user_size_t nbyte); }
- SYS_WRITE = 4 // { user_ssize_t write(int fd, user_addr_t cbuf, user_size_t nbyte); }
- SYS_OPEN = 5 // { int open(user_addr_t path, int flags, int mode); }
- SYS_CLOSE = 6 // { int close(int fd); }
- SYS_WAIT4 = 7 // { int wait4(int pid, user_addr_t status, int options, user_addr_t rusage); }
- // SYS_NOSYS = 8; // { int nosys(void); } { old creat }
- SYS_LINK = 9 // { int link(user_addr_t path, user_addr_t link); }
- SYS_UNLINK = 10 // { int unlink(user_addr_t path); }
- // SYS_NOSYS = 11; // { int nosys(void); } { old execv }
- SYS_CHDIR = 12 // { int chdir(user_addr_t path); }
- SYS_FCHDIR = 13 // { int fchdir(int fd); }
- SYS_MKNOD = 14 // { int mknod(user_addr_t path, int mode, int dev); }
- SYS_CHMOD = 15 // { int chmod(user_addr_t path, int mode); }
- SYS_CHOWN = 16 // { int chown(user_addr_t path, int uid, int gid); }
- SYS_OGETFSSTAT = 18 // { int ogetfsstat(user_addr_t buf, int bufsize, int flags); }
- SYS_GETFSSTAT = 18 // { int getfsstat(user_addr_t buf, int bufsize, int flags); }
- // SYS_NOSYS = 19; // { int nosys(void); } { old lseek }
- SYS_GETPID = 20 // { int getpid(void); }
- // SYS_NOSYS = 21; // { int nosys(void); } { old mount }
- // SYS_NOSYS = 22; // { int nosys(void); } { old umount }
- SYS_SETUID = 23 // { int setuid(uid_t uid); }
- SYS_GETUID = 24 // { int getuid(void); }
- SYS_GETEUID = 25 // { int geteuid(void); }
- SYS_PTRACE = 26 // { int ptrace(int req, pid_t pid, caddr_t addr, int data); }
- SYS_RECVMSG = 27 // { int recvmsg(int s, struct msghdr *msg, int flags); }
- SYS_SENDMSG = 28 // { int sendmsg(int s, caddr_t msg, int flags); }
- SYS_RECVFROM = 29 // { int recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, int *fromlenaddr); }
- SYS_ACCEPT = 30 // { int accept(int s, caddr_t name, socklen_t *anamelen); }
- SYS_GETPEERNAME = 31 // { int getpeername(int fdes, caddr_t asa, socklen_t *alen); }
- SYS_GETSOCKNAME = 32 // { int getsockname(int fdes, caddr_t asa, socklen_t *alen); }
- // SYS_NOSYS = 27; // { int nosys(void); }
- // SYS_NOSYS = 28; // { int nosys(void); }
- // SYS_NOSYS = 29; // { int nosys(void); }
- // SYS_NOSYS = 30; // { int nosys(void); }
- // SYS_NOSYS = 31; // { int nosys(void); }
- // SYS_NOSYS = 32; // { int nosys(void); }
- SYS_ACCESS = 33 // { int access(user_addr_t path, int flags); }
- SYS_CHFLAGS = 34 // { int chflags(char *path, int flags); }
- SYS_FCHFLAGS = 35 // { int fchflags(int fd, int flags); }
- SYS_SYNC = 36 // { int sync(void); }
- SYS_KILL = 37 // { int kill(int pid, int signum, int posix); }
- // SYS_NOSYS = 38; // { int nosys(void); } { old stat }
- SYS_GETPPID = 39 // { int getppid(void); }
- // SYS_NOSYS = 40; // { int nosys(void); } { old lstat }
- SYS_DUP = 41 // { int dup(u_int fd); }
- SYS_PIPE = 42 // { int pipe(void); }
- SYS_GETEGID = 43 // { int getegid(void); }
- SYS_PROFIL = 44 // { int profil(short *bufbase, size_t bufsize, u_long pcoffset, u_int pcscale); }
- // SYS_NOSYS = 45; // { int nosys(void); } { old ktrace }
- SYS_SIGACTION = 46 // { int sigaction(int signum, struct __sigaction *nsa, struct sigaction *osa); }
- SYS_GETGID = 47 // { int getgid(void); }
- SYS_SIGPROCMASK = 48 // { int sigprocmask(int how, user_addr_t mask, user_addr_t omask); }
- SYS_GETLOGIN = 49 // { int getlogin(char *namebuf, u_int namelen); }
- SYS_SETLOGIN = 50 // { int setlogin(char *namebuf); }
- SYS_ACCT = 51 // { int acct(char *path); }
- SYS_SIGPENDING = 52 // { int sigpending(struct sigvec *osv); }
- SYS_SIGALTSTACK = 53 // { int sigaltstack(struct sigaltstack *nss, struct sigaltstack *oss); }
- SYS_IOCTL = 54 // { int ioctl(int fd, u_long com, caddr_t data); }
- SYS_REBOOT = 55 // { int reboot(int opt, char *command); }
- SYS_REVOKE = 56 // { int revoke(char *path); }
- SYS_SYMLINK = 57 // { int symlink(char *path, char *link); }
- SYS_READLINK = 58 // { int readlink(char *path, char *buf, int count); }
- SYS_EXECVE = 59 // { int execve(char *fname, char **argp, char **envp); }
- SYS_UMASK = 60 // { int umask(int newmask); }
- SYS_CHROOT = 61 // { int chroot(user_addr_t path); }
- // SYS_NOSYS = 62; // { int nosys(void); } { old fstat }
- // SYS_NOSYS = 63; // { int nosys(void); } { used internally, reserved }
- // SYS_NOSYS = 64; // { int nosys(void); } { old getpagesize }
- SYS_MSYNC = 65 // { int msync(caddr_t addr, size_t len, int flags); }
- SYS_VFORK = 66 // { int vfork(void); }
- // SYS_NOSYS = 67; // { int nosys(void); } { old vread }
- // SYS_NOSYS = 68; // { int nosys(void); } { old vwrite }
- SYS_SBRK = 69 // { int sbrk(int incr) NO_SYSCALL_STUB; }
- SYS_SSTK = 70 // { int sstk(int incr) NO_SYSCALL_STUB; }
- // SYS_NOSYS = 71; // { int nosys(void); } { old mmap }
- SYS_OVADVISE = 72 // { int ovadvise(void) NO_SYSCALL_STUB; } { old vadvise }
- SYS_MUNMAP = 73 // { int munmap(caddr_t addr, size_t len); }
- SYS_MPROTECT = 74 // { int mprotect(caddr_t addr, size_t len, int prot); }
- SYS_MADVISE = 75 // { int madvise(caddr_t addr, size_t len, int behav); }
- // SYS_NOSYS = 76; // { int nosys(void); } { old vhangup }
- // SYS_NOSYS = 77; // { int nosys(void); } { old vlimit }
- SYS_MINCORE = 78 // { int mincore(user_addr_t addr, user_size_t len, user_addr_t vec); }
- SYS_GETGROUPS = 79 // { int getgroups(u_int gidsetsize, gid_t *gidset); }
- SYS_SETGROUPS = 80 // { int setgroups(u_int gidsetsize, gid_t *gidset); }
- SYS_GETPGRP = 81 // { int getpgrp(void); }
- SYS_SETPGID = 82 // { int setpgid(int pid, int pgid); }
- SYS_SETITIMER = 83 // { int setitimer(u_int which, struct itimerval *itv, struct itimerval *oitv); }
- // SYS_NOSYS = 84; // { int nosys(void); } { old wait }
- SYS_SWAPON = 85 // { int swapon(void); }
- SYS_GETITIMER = 86 // { int getitimer(u_int which, struct itimerval *itv); }
- // SYS_NOSYS = 87; // { int nosys(void); } { old gethostname }
- // SYS_NOSYS = 88; // { int nosys(void); } { old sethostname }
- SYS_GETDTABLESIZE = 89 // { int getdtablesize(void); }
- SYS_DUP2 = 90 // { int dup2(u_int from, u_int to); }
- // SYS_NOSYS = 91; // { int nosys(void); } { old getdopt }
- SYS_FCNTL = 92 // { int fcntl(int fd, int cmd, long arg); }
- SYS_SELECT = 93 // { int select(int nd, u_int32_t *in, u_int32_t *ou, u_int32_t *ex, struct timeval *tv); }
- // SYS_NOSYS = 94; // { int nosys(void); } { old setdopt }
- SYS_FSYNC = 95 // { int fsync(int fd); }
- SYS_SETPRIORITY = 96 // { int setpriority(int which, id_t who, int prio); }
- SYS_SOCKET = 97 // { int socket(int domain, int type, int protocol); }
- SYS_CONNECT = 98 // { int connect(int s, caddr_t name, socklen_t namelen); }
- // SYS_NOSYS = 97; // { int nosys(void); }
- // SYS_NOSYS = 98; // { int nosys(void); }
- // SYS_NOSYS = 99; // { int nosys(void); } { old accept }
- SYS_GETPRIORITY = 100 // { int getpriority(int which, id_t who); }
- // SYS_NOSYS = 101; // { int nosys(void); } { old send }
- // SYS_NOSYS = 102; // { int nosys(void); } { old recv }
- // SYS_NOSYS = 103; // { int nosys(void); } { old sigreturn }
- SYS_BIND = 104 // { int bind(int s, caddr_t name, socklen_t namelen); }
- SYS_SETSOCKOPT = 105 // { int setsockopt(int s, int level, int name, caddr_t val, socklen_t valsize); }
- SYS_LISTEN = 106 // { int listen(int s, int backlog); }
- // SYS_NOSYS = 104; // { int nosys(void); }
- // SYS_NOSYS = 105; // { int nosys(void); }
- // SYS_NOSYS = 106; // { int nosys(void); }
- // SYS_NOSYS = 107; // { int nosys(void); } { old vtimes }
- // SYS_NOSYS = 108; // { int nosys(void); } { old sigvec }
- // SYS_NOSYS = 109; // { int nosys(void); } { old sigblock }
- // SYS_NOSYS = 110; // { int nosys(void); } { old sigsetmask }
- SYS_SIGSUSPEND = 111 // { int sigsuspend(sigset_t mask); }
- // SYS_NOSYS = 112; // { int nosys(void); } { old sigstack }
- // SYS_NOSYS = 113; // { int nosys(void); } { old recvmsg }
- // SYS_NOSYS = 114; // { int nosys(void); } { old sendmsg }
- // SYS_NOSYS = 113; // { int nosys(void); }
- // SYS_NOSYS = 114; // { int nosys(void); }
- // SYS_NOSYS = 115; // { int nosys(void); } { old vtrace }
- SYS_GETTIMEOFDAY = 116 // { int gettimeofday(struct timeval *tp, struct timezone *tzp); }
- SYS_GETRUSAGE = 117 // { int getrusage(int who, struct rusage *rusage); }
- SYS_GETSOCKOPT = 118 // { int getsockopt(int s, int level, int name, caddr_t val, socklen_t *avalsize); }
- // SYS_NOSYS = 118; // { int nosys(void); }
- // SYS_NOSYS = 119; // { int nosys(void); } { old resuba }
- SYS_READV = 120 // { user_ssize_t readv(int fd, struct iovec *iovp, u_int iovcnt); }
- SYS_WRITEV = 121 // { user_ssize_t writev(int fd, struct iovec *iovp, u_int iovcnt); }
- SYS_SETTIMEOFDAY = 122 // { int settimeofday(struct timeval *tv, struct timezone *tzp); }
- SYS_FCHOWN = 123 // { int fchown(int fd, int uid, int gid); }
- SYS_FCHMOD = 124 // { int fchmod(int fd, int mode); }
- // SYS_NOSYS = 125; // { int nosys(void); } { old recvfrom }
- SYS_SETREUID = 126 // { int setreuid(uid_t ruid, uid_t euid); }
- SYS_SETREGID = 127 // { int setregid(gid_t rgid, gid_t egid); }
- SYS_RENAME = 128 // { int rename(char *from, char *to); }
- // SYS_NOSYS = 129; // { int nosys(void); } { old truncate }
- // SYS_NOSYS = 130; // { int nosys(void); } { old ftruncate }
- SYS_FLOCK = 131 // { int flock(int fd, int how); }
- SYS_MKFIFO = 132 // { int mkfifo(user_addr_t path, int mode); }
- SYS_SENDTO = 133 // { int sendto(int s, caddr_t buf, size_t len, int flags, caddr_t to, socklen_t tolen); }
- SYS_SHUTDOWN = 134 // { int shutdown(int s, int how); }
- SYS_SOCKETPAIR = 135 // { int socketpair(int domain, int type, int protocol, int *rsv); }
- // SYS_NOSYS = 133; // { int nosys(void); }
- // SYS_NOSYS = 134; // { int nosys(void); }
- // SYS_NOSYS = 135; // { int nosys(void); }
- SYS_MKDIR = 136 // { int mkdir(user_addr_t path, int mode); }
- SYS_RMDIR = 137 // { int rmdir(char *path); }
- SYS_UTIMES = 138 // { int utimes(char *path, struct timeval *tptr); }
- SYS_FUTIMES = 139 // { int futimes(int fd, struct timeval *tptr); }
- SYS_ADJTIME = 140 // { int adjtime(struct timeval *delta, struct timeval *olddelta); }
- // SYS_NOSYS = 141; // { int nosys(void); } { old getpeername }
- SYS_GETHOSTUUID = 142 // { int gethostuuid(unsigned char *uuid_buf, const struct timespec *timeoutp); }
- // SYS_NOSYS = 143; // { int nosys(void); } { old sethostid }
- // SYS_NOSYS = 144; // { int nosys(void); } { old getrlimit }
- // SYS_NOSYS = 145; // { int nosys(void); } { old setrlimit }
- // SYS_NOSYS = 146; // { int nosys(void); } { old killpg }
- SYS_SETSID = 147 // { int setsid(void); }
- // SYS_NOSYS = 148; // { int nosys(void); } { old setquota }
- // SYS_NOSYS = 149; // { int nosys(void); } { old qquota }
- // SYS_NOSYS = 150; // { int nosys(void); } { old getsockname }
- SYS_GETPGID = 151 // { int getpgid(pid_t pid); }
- SYS_SETPRIVEXEC = 152 // { int setprivexec(int flag); }
- SYS_PREAD = 153 // { user_ssize_t pread(int fd, user_addr_t buf, user_size_t nbyte, off_t offset); }
- SYS_PWRITE = 154 // { user_ssize_t pwrite(int fd, user_addr_t buf, user_size_t nbyte, off_t offset); }
- SYS_NFSSVC = 155 // { int nfssvc(int flag, caddr_t argp); }
- // SYS_NOSYS = 155; // { int nosys(void); }
- // SYS_NOSYS = 156; // { int nosys(void); } { old getdirentries }
- SYS_STATFS = 157 // { int statfs(char *path, struct statfs *buf); }
- SYS_FSTATFS = 158 // { int fstatfs(int fd, struct statfs *buf); }
- SYS_UNMOUNT = 159 // { int unmount(user_addr_t path, int flags); }
- // SYS_NOSYS = 160; // { int nosys(void); } { old async_daemon }
- SYS_GETFH = 161 // { int getfh(char *fname, fhandle_t *fhp); }
- // SYS_NOSYS = 161; // { int nosys(void); }
- // SYS_NOSYS = 162; // { int nosys(void); } { old getdomainname }
- // SYS_NOSYS = 163; // { int nosys(void); } { old setdomainname }
- // SYS_NOSYS = 164; // { int nosys(void); }
- SYS_QUOTACTL = 165 // { int quotactl(const char *path, int cmd, int uid, caddr_t arg); }
- // SYS_NOSYS = 166; // { int nosys(void); } { old exportfs }
- SYS_MOUNT = 167 // { int mount(char *type, char *path, int flags, caddr_t data); }
- // SYS_NOSYS = 168; // { int nosys(void); } { old ustat }
- SYS_CSOPS = 169 // { int csops(pid_t pid, uint32_t ops, user_addr_t useraddr, user_size_t usersize); }
- // SYS_NOSYS = 171; // { int nosys(void); } { old wait3 }
- // SYS_NOSYS = 172; // { int nosys(void); } { old rpause }
- SYS_WAITID = 173 // { int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options); }
- // SYS_NOSYS = 174; // { int nosys(void); } { old getdents }
- // SYS_NOSYS = 175; // { int nosys(void); } { old gc_control }
- SYS_ADD_PROFIL = 176 // { int add_profil(short *bufbase, size_t bufsize, u_long pcoffset, u_int pcscale); }
- // SYS_NOSYS = 177; // { int nosys(void); }
- // SYS_NOSYS = 178; // { int nosys(void); }
- // SYS_NOSYS = 179; // { int nosys(void); }
- SYS_KDEBUG_TRACE = 180 // { int kdebug_trace(int code, int arg1, int arg2, int arg3, int arg4, int arg5) NO_SYSCALL_STUB; }
- SYS_SETGID = 181 // { int setgid(gid_t gid); }
- SYS_SETEGID = 182 // { int setegid(gid_t egid); }
- SYS_SETEUID = 183 // { int seteuid(uid_t euid); }
- SYS_SIGRETURN = 184 // { int sigreturn(struct ucontext *uctx, int infostyle); }
- // SYS_NOSYS = 186; // { int nosys(void); }
- // SYS_NOSYS = 187; // { int nosys(void); }
- SYS_STAT = 188 // { int stat(user_addr_t path, user_addr_t ub); }
- SYS_FSTAT = 189 // { int fstat(int fd, user_addr_t ub); }
- SYS_LSTAT = 190 // { int lstat(user_addr_t path, user_addr_t ub); }
- SYS_PATHCONF = 191 // { int pathconf(char *path, int name); }
- SYS_FPATHCONF = 192 // { int fpathconf(int fd, int name); }
- // SYS_NOSYS = 193; // { int nosys(void); }
- SYS_GETRLIMIT = 194 // { int getrlimit(u_int which, struct rlimit *rlp); }
- SYS_SETRLIMIT = 195 // { int setrlimit(u_int which, struct rlimit *rlp); }
- SYS_GETDIRENTRIES = 196 // { int getdirentries(int fd, char *buf, u_int count, long *basep); }
- SYS_MMAP = 197 // { user_addr_t mmap(caddr_t addr, size_t len, int prot, int flags, int fd, off_t pos); }
- // SYS_NOSYS = 198; // { int nosys(void); } { __syscall }
- SYS_LSEEK = 199 // { off_t lseek(int fd, off_t offset, int whence); }
- SYS_TRUNCATE = 200 // { int truncate(char *path, off_t length); }
- SYS_FTRUNCATE = 201 // { int ftruncate(int fd, off_t length); }
- SYS___SYSCTL = 202 // { int __sysctl(int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen); }
- SYS_MLOCK = 203 // { int mlock(caddr_t addr, size_t len); }
- SYS_MUNLOCK = 204 // { int munlock(caddr_t addr, size_t len); }
- SYS_UNDELETE = 205 // { int undelete(user_addr_t path); }
- SYS_ATSOCKET = 206 // { int ATsocket(int proto); }
- // SYS_NOSYS = 213; // { int nosys(void); } { Reserved for AppleTalk }
- // SYS_NOSYS = 206; // { int nosys(void); }
- // SYS_NOSYS = 207; // { int nosys(void); }
- // SYS_NOSYS = 208; // { int nosys(void); }
- // SYS_NOSYS = 209; // { int nosys(void); }
- // SYS_NOSYS = 210; // { int nosys(void); }
- // SYS_NOSYS = 211; // { int nosys(void); }
- // SYS_NOSYS = 212; // { int nosys(void); }
- // SYS_NOSYS = 213; // { int nosys(void); } { Reserved for AppleTalk }
- SYS_KQUEUE_FROM_PORTSET_NP = 214 // { int kqueue_from_portset_np(int portset); }
- SYS_KQUEUE_PORTSET_NP = 215 // { int kqueue_portset_np(int fd); }
- SYS_GETATTRLIST = 220 // { int getattrlist(const char *path, struct attrlist *alist, void *attributeBuffer, size_t bufferSize, u_long options); }
- SYS_SETATTRLIST = 221 // { int setattrlist(const char *path, struct attrlist *alist, void *attributeBuffer, size_t bufferSize, u_long options); }
- SYS_GETDIRENTRIESATTR = 222 // { int getdirentriesattr(int fd, struct attrlist *alist, void *buffer, size_t buffersize, u_long *count, u_long *basep, u_long *newstate, u_long options); }
- SYS_EXCHANGEDATA = 223 // { int exchangedata(const char *path1, const char *path2, u_long options); }
- // SYS_NOSYS = 224; // { int nosys(void); } { was checkuseraccess }
- SYS_SEARCHFS = 225 // { int searchfs(const char *path, struct fssearchblock *searchblock, u_long *nummatches, u_long scriptcode, u_long options, struct searchstate *state); }
- SYS_DELETE = 226 // { int delete(user_addr_t path) NO_SYSCALL_STUB; } { private delete (Carbon semantics) }
- SYS_COPYFILE = 227 // { int copyfile(char *from, char *to, int mode, int flags) NO_SYSCALL_STUB; }
- // SYS_NOSYS = 228; // { int nosys(void); }
- // SYS_NOSYS = 229; // { int nosys(void); }
- SYS_POLL = 230 // { int poll(struct pollfd *fds, u_int nfds, int timeout); }
- SYS_WATCHEVENT = 231 // { int watchevent(struct eventreq *u_req, int u_eventmask); }
- SYS_WAITEVENT = 232 // { int waitevent(struct eventreq *u_req, struct timeval *tv); }
- SYS_MODWATCH = 233 // { int modwatch(struct eventreq *u_req, int u_eventmask); }
- SYS_GETXATTR = 234 // { user_ssize_t getxattr(user_addr_t path, user_addr_t attrname, user_addr_t value, size_t size, uint32_t position, int options); }
- SYS_FGETXATTR = 235 // { user_ssize_t fgetxattr(int fd, user_addr_t attrname, user_addr_t value, size_t size, uint32_t position, int options); }
- SYS_SETXATTR = 236 // { int setxattr(user_addr_t path, user_addr_t attrname, user_addr_t value, size_t size, uint32_t position, int options); }
- SYS_FSETXATTR = 237 // { int fsetxattr(int fd, user_addr_t attrname, user_addr_t value, size_t size, uint32_t position, int options); }
- SYS_REMOVEXATTR = 238 // { int removexattr(user_addr_t path, user_addr_t attrname, int options); }
- SYS_FREMOVEXATTR = 239 // { int fremovexattr(int fd, user_addr_t attrname, int options); }
- SYS_LISTXATTR = 240 // { user_ssize_t listxattr(user_addr_t path, user_addr_t namebuf, size_t bufsize, int options); }
- SYS_FLISTXATTR = 241 // { user_ssize_t flistxattr(int fd, user_addr_t namebuf, size_t bufsize, int options); }
- SYS_FSCTL = 242 // { int fsctl(const char *path, u_long cmd, caddr_t data, u_long options); }
- SYS_INITGROUPS = 243 // { int initgroups(u_int gidsetsize, gid_t *gidset, int gmuid); }
- SYS_POSIX_SPAWN = 244 // { int posix_spawn(pid_t *pid, const char *path, const struct _posix_spawn_args_desc *adesc, char **argv, char **envp); }
- // SYS_NOSYS = 245; // { int nosys(void); }
- // SYS_NOSYS = 246; // { int nosys(void); }
- SYS_NFSCLNT = 247 // { int nfsclnt(int flag, caddr_t argp); }
- // SYS_NOSYS = 247; // { int nosys(void); }
- SYS_FHOPEN = 248 // { int fhopen(const struct fhandle *u_fhp, int flags); }
- // SYS_NOSYS = 248; // { int nosys(void); }
- // SYS_NOSYS = 249; // { int nosys(void); }
- SYS_MINHERIT = 250 // { int minherit(void *addr, size_t len, int inherit); }
- SYS_SEMSYS = 251 // { int semsys(u_int which, int a2, int a3, int a4, int a5); }
- // SYS_NOSYS = 251; // { int nosys(void); }
- SYS_MSGSYS = 252 // { int msgsys(u_int which, int a2, int a3, int a4, int a5); }
- // SYS_NOSYS = 252; // { int nosys(void); }
- SYS_SHMSYS = 253 // { int shmsys(u_int which, int a2, int a3, int a4); }
- // SYS_NOSYS = 253; // { int nosys(void); }
- SYS_SEMCTL = 254 // { int semctl(int semid, int semnum, int cmd, semun_t arg); }
- SYS_SEMGET = 255 // { int semget(key_t key, int nsems, int semflg); }
- SYS_SEMOP = 256 // { int semop(int semid, struct sembuf *sops, int nsops); }
- // SYS_NOSYS = 257; // { int nosys(void); }
- // SYS_NOSYS = 254; // { int nosys(void); }
- // SYS_NOSYS = 255; // { int nosys(void); }
- // SYS_NOSYS = 256; // { int nosys(void); }
- // SYS_NOSYS = 257; // { int nosys(void); }
- SYS_MSGCTL = 258 // { int msgctl(int msqid, int cmd, struct msqid_ds *buf); }
- SYS_MSGGET = 259 // { int msgget(key_t key, int msgflg); }
- SYS_MSGSND = 260 // { int msgsnd(int msqid, void *msgp, size_t msgsz, int msgflg); }
- SYS_MSGRCV = 261 // { user_ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); }
- // SYS_NOSYS = 258; // { int nosys(void); }
- // SYS_NOSYS = 259; // { int nosys(void); }
- // SYS_NOSYS = 260; // { int nosys(void); }
- // SYS_NOSYS = 261; // { int nosys(void); }
- SYS_SHMAT = 262 // { user_addr_t shmat(int shmid, void *shmaddr, int shmflg); }
- SYS_SHMCTL = 263 // { int shmctl(int shmid, int cmd, struct shmid_ds *buf); }
- SYS_SHMDT = 264 // { int shmdt(void *shmaddr); }
- SYS_SHMGET = 265 // { int shmget(key_t key, size_t size, int shmflg); }
- // SYS_NOSYS = 262; // { int nosys(void); }
- // SYS_NOSYS = 263; // { int nosys(void); }
- // SYS_NOSYS = 264; // { int nosys(void); }
- // SYS_NOSYS = 265; // { int nosys(void); }
- SYS_SHM_OPEN = 266 // { int shm_open(const char *name, int oflag, int mode); }
- SYS_SHM_UNLINK = 267 // { int shm_unlink(const char *name); }
- SYS_SEM_OPEN = 268 // { user_addr_t sem_open(const char *name, int oflag, int mode, int value); }
- SYS_SEM_CLOSE = 269 // { int sem_close(sem_t *sem); }
- SYS_SEM_UNLINK = 270 // { int sem_unlink(const char *name); }
- SYS_SEM_WAIT = 271 // { int sem_wait(sem_t *sem); }
- SYS_SEM_TRYWAIT = 272 // { int sem_trywait(sem_t *sem); }
- SYS_SEM_POST = 273 // { int sem_post(sem_t *sem); }
- SYS_SEM_GETVALUE = 274 // { int sem_getvalue(sem_t *sem, int *sval); }
- SYS_SEM_INIT = 275 // { int sem_init(sem_t *sem, int phsared, u_int value); }
- SYS_SEM_DESTROY = 276 // { int sem_destroy(sem_t *sem); }
- SYS_OPEN_EXTENDED = 277 // { int open_extended(user_addr_t path, int flags, uid_t uid, gid_t gid, int mode, user_addr_t xsecurity) NO_SYSCALL_STUB; }
- SYS_UMASK_EXTENDED = 278 // { int umask_extended(int newmask, user_addr_t xsecurity) NO_SYSCALL_STUB; }
- SYS_STAT_EXTENDED = 279 // { int stat_extended(user_addr_t path, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; }
- SYS_LSTAT_EXTENDED = 280 // { int lstat_extended(user_addr_t path, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; }
- SYS_FSTAT_EXTENDED = 281 // { int fstat_extended(int fd, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; }
- SYS_CHMOD_EXTENDED = 282 // { int chmod_extended(user_addr_t path, uid_t uid, gid_t gid, int mode, user_addr_t xsecurity) NO_SYSCALL_STUB; }
- SYS_FCHMOD_EXTENDED = 283 // { int fchmod_extended(int fd, uid_t uid, gid_t gid, int mode, user_addr_t xsecurity) NO_SYSCALL_STUB; }
- SYS_ACCESS_EXTENDED = 284 // { int access_extended(user_addr_t entries, size_t size, user_addr_t results, uid_t uid) NO_SYSCALL_STUB; }
- SYS_SETTID = 285 // { int settid(uid_t uid, gid_t gid) NO_SYSCALL_STUB; }
- SYS_GETTID = 286 // { int gettid(uid_t *uidp, gid_t *gidp) NO_SYSCALL_STUB; }
- SYS_SETSGROUPS = 287 // { int setsgroups(int setlen, user_addr_t guidset) NO_SYSCALL_STUB; }
- SYS_GETSGROUPS = 288 // { int getsgroups(user_addr_t setlen, user_addr_t guidset) NO_SYSCALL_STUB; }
- SYS_SETWGROUPS = 289 // { int setwgroups(int setlen, user_addr_t guidset) NO_SYSCALL_STUB; }
- SYS_GETWGROUPS = 290 // { int getwgroups(user_addr_t setlen, user_addr_t guidset) NO_SYSCALL_STUB; }
- SYS_MKFIFO_EXTENDED = 291 // { int mkfifo_extended(user_addr_t path, uid_t uid, gid_t gid, int mode, user_addr_t xsecurity) NO_SYSCALL_STUB; }
- SYS_MKDIR_EXTENDED = 292 // { int mkdir_extended(user_addr_t path, uid_t uid, gid_t gid, int mode, user_addr_t xsecurity) NO_SYSCALL_STUB; }
- SYS_IDENTITYSVC = 293 // { int identitysvc(int opcode, user_addr_t message) NO_SYSCALL_STUB; }
- SYS_SHARED_REGION_CHECK_NP = 294 // { int shared_region_check_np(uint64_t *start_address) NO_SYSCALL_STUB; }
- SYS_SHARED_REGION_MAP_NP = 295 // { int shared_region_map_np(int fd, uint32_t count, const struct shared_file_mapping_np *mappings) NO_SYSCALL_STUB; }
- // SYS_NOSYS = 296; // { int nosys(void); } { old load_shared_file }
- // SYS_NOSYS = 297; // { int nosys(void); } { old reset_shared_file }
- // SYS_NOSYS = 298; // { int nosys(void); } { old new_system_shared_regions }
- // SYS_ENOSYS = 299; // { int enosys(void); } { old shared_region_map_file_np }
- // SYS_ENOSYS = 300; // { int enosys(void); } { old shared_region_make_private_np }
- SYS___PTHREAD_MUTEX_DESTROY = 301 // { int __pthread_mutex_destroy(int mutexid); }
- SYS___PTHREAD_MUTEX_INIT = 302 // { int __pthread_mutex_init(user_addr_t mutex, user_addr_t attr); }
- SYS___PTHREAD_MUTEX_LOCK = 303 // { int __pthread_mutex_lock(int mutexid); }
- SYS___PTHREAD_MUTEX_TRYLOCK = 304 // { int __pthread_mutex_trylock(int mutexid); }
- SYS___PTHREAD_MUTEX_UNLOCK = 305 // { int __pthread_mutex_unlock(int mutexid); }
- SYS___PTHREAD_COND_INIT = 306 // { int __pthread_cond_init(user_addr_t cond, user_addr_t attr); }
- SYS___PTHREAD_COND_DESTROY = 307 // { int __pthread_cond_destroy(int condid); }
- SYS___PTHREAD_COND_BROADCAST = 308 // { int __pthread_cond_broadcast(int condid); }
- SYS___PTHREAD_COND_SIGNAL = 309 // { int __pthread_cond_signal(int condid); }
- SYS_GETSID = 310 // { int getsid(pid_t pid); }
- SYS_SETTID_WITH_PID = 311 // { int settid_with_pid(pid_t pid, int assume) NO_SYSCALL_STUB; }
- SYS___PTHREAD_COND_TIMEDWAIT = 312 // { int __pthread_cond_timedwait(int condid, int mutexid, user_addr_t abstime); }
- SYS_AIO_FSYNC = 313 // { int aio_fsync(int op, user_addr_t aiocbp); }
- SYS_AIO_RETURN = 314 // { user_ssize_t aio_return(user_addr_t aiocbp); }
- SYS_AIO_SUSPEND = 315 // { int aio_suspend(user_addr_t aiocblist, int nent, user_addr_t timeoutp); }
- SYS_AIO_CANCEL = 316 // { int aio_cancel(int fd, user_addr_t aiocbp); }
- SYS_AIO_ERROR = 317 // { int aio_error(user_addr_t aiocbp); }
- SYS_AIO_READ = 318 // { int aio_read(user_addr_t aiocbp); }
- SYS_AIO_WRITE = 319 // { int aio_write(user_addr_t aiocbp); }
- SYS_LIO_LISTIO = 320 // { int lio_listio(int mode, user_addr_t aiocblist, int nent, user_addr_t sigp); }
- SYS___PTHREAD_COND_WAIT = 321 // { int __pthread_cond_wait(int condid, int mutexid); }
- SYS_IOPOLICYSYS = 322 // { int iopolicysys(int cmd, void *arg) NO_SYSCALL_STUB; }
- // SYS_NOSYS = 323; // { int nosys(void); }
- SYS_MLOCKALL = 324 // { int mlockall(int how); }
- SYS_MUNLOCKALL = 325 // { int munlockall(int how); }
- // SYS_NOSYS = 326; // { int nosys(void); }
- SYS_ISSETUGID = 327 // { int issetugid(void); }
- SYS___PTHREAD_KILL = 328 // { int __pthread_kill(int thread_port, int sig); }
- SYS___PTHREAD_SIGMASK = 329 // { int __pthread_sigmask(int how, user_addr_t set, user_addr_t oset); }
- SYS___SIGWAIT = 330 // { int __sigwait(user_addr_t set, user_addr_t sig); }
- SYS___DISABLE_THREADSIGNAL = 331 // { int __disable_threadsignal(int value); }
- SYS___PTHREAD_MARKCANCEL = 332 // { int __pthread_markcancel(int thread_port); }
- SYS___PTHREAD_CANCELED = 333 // { int __pthread_canceled(int action); }
- SYS___SEMWAIT_SIGNAL = 334 // { int __semwait_signal(int cond_sem, int mutex_sem, int timeout, int relative, time_t tv_sec, int32_t tv_nsec); }
- // SYS_NOSYS = 335; // { int nosys(void); } { old utrace }
- SYS_PROC_INFO = 336 // { int proc_info(int32_t callnum,int32_t pid,uint32_t flavor, uint64_t arg,user_addr_t buffer,int32_t buffersize) NO_SYSCALL_STUB; }
- SYS_SENDFILE = 337 // { int sendfile(int fd, int s, off_t offset, off_t *nbytes, struct sf_hdtr *hdtr, int flags); }
- // SYS_NOSYS = 337; // { int nosys(void); }
- SYS_STAT64 = 338 // { int stat64(user_addr_t path, user_addr_t ub); }
- SYS_FSTAT64 = 339 // { int fstat64(int fd, user_addr_t ub); }
- SYS_LSTAT64 = 340 // { int lstat64(user_addr_t path, user_addr_t ub); }
- SYS_STAT64_EXTENDED = 341 // { int stat64_extended(user_addr_t path, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; }
- SYS_LSTAT64_EXTENDED = 342 // { int lstat64_extended(user_addr_t path, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; }
- SYS_FSTAT64_EXTENDED = 343 // { int fstat64_extended(int fd, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) NO_SYSCALL_STUB; }
- SYS_GETDIRENTRIES64 = 344 // { user_ssize_t getdirentries64(int fd, void *buf, user_size_t bufsize, off_t *position) NO_SYSCALL_STUB; }
- SYS_STATFS64 = 345 // { int statfs64(char *path, struct statfs64 *buf); }
- SYS_FSTATFS64 = 346 // { int fstatfs64(int fd, struct statfs64 *buf); }
- SYS_GETFSSTAT64 = 347 // { int getfsstat64(user_addr_t buf, int bufsize, int flags); }
- SYS___PTHREAD_CHDIR = 348 // { int __pthread_chdir(user_addr_t path); }
- SYS___PTHREAD_FCHDIR = 349 // { int __pthread_fchdir(int fd); }
- SYS_AUDIT = 350 // { int audit(void *record, int length); }
- SYS_AUDITON = 351 // { int auditon(int cmd, void *data, int length); }
- // SYS_NOSYS = 352; // { int nosys(void); }
- SYS_GETAUID = 353 // { int getauid(au_id_t *auid); }
- SYS_SETAUID = 354 // { int setauid(au_id_t *auid); }
- SYS_GETAUDIT = 355 // { int getaudit(struct auditinfo *auditinfo); }
- SYS_SETAUDIT = 356 // { int setaudit(struct auditinfo *auditinfo); }
- SYS_GETAUDIT_ADDR = 357 // { int getaudit_addr(struct auditinfo_addr *auditinfo_addr, int length); }
- SYS_SETAUDIT_ADDR = 358 // { int setaudit_addr(struct auditinfo_addr *auditinfo_addr, int length); }
- SYS_AUDITCTL = 359 // { int auditctl(char *path); }
- // SYS_NOSYS = 350; // { int nosys(void); }
- // SYS_NOSYS = 351; // { int nosys(void); }
- // SYS_NOSYS = 352; // { int nosys(void); }
- // SYS_NOSYS = 353; // { int nosys(void); }
- // SYS_NOSYS = 354; // { int nosys(void); }
- // SYS_NOSYS = 355; // { int nosys(void); }
- // SYS_NOSYS = 356; // { int nosys(void); }
- // SYS_NOSYS = 357; // { int nosys(void); }
- // SYS_NOSYS = 358; // { int nosys(void); }
- // SYS_NOSYS = 359; // { int nosys(void); }
- SYS_BSDTHREAD_CREATE = 360 // { user_addr_t bsdthread_create(user_addr_t func, user_addr_t func_arg, user_addr_t stack, user_addr_t pthread, uint32_t flags) NO_SYSCALL_STUB; }
- SYS_BSDTHREAD_TERMINATE = 361 // { int bsdthread_terminate(user_addr_t stackaddr, size_t freesize, uint32_t port, uint32_t sem) NO_SYSCALL_STUB; }
- SYS_KQUEUE = 362 // { int kqueue(void); }
- SYS_KEVENT = 363 // { int kevent(int fd, const struct kevent *changelist, int nchanges, struct kevent *eventlist, int nevents, const struct timespec *timeout); }
- SYS_LCHOWN = 364 // { int lchown(user_addr_t path, uid_t owner, gid_t group); }
- SYS_STACK_SNAPSHOT = 365 // { int stack_snapshot(pid_t pid, user_addr_t tracebuf, uint32_t tracebuf_size, uint32_t options) NO_SYSCALL_STUB; }
- SYS_BSDTHREAD_REGISTER = 366 // { int bsdthread_register(user_addr_t threadstart, user_addr_t wqthread, int pthsize) NO_SYSCALL_STUB; }
- SYS_WORKQ_OPEN = 367 // { int workq_open(void) NO_SYSCALL_STUB; }
- SYS_WORKQ_OPS = 368 // { int workq_ops(int options, user_addr_t item, int prio) NO_SYSCALL_STUB; }
- // SYS_NOSYS = 369; // { int nosys(void); }
- // SYS_NOSYS = 370; // { int nosys(void); }
- // SYS_NOSYS = 371; // { int nosys(void); }
- // SYS_NOSYS = 372; // { int nosys(void); }
- // SYS_NOSYS = 373; // { int nosys(void); }
- // SYS_NOSYS = 374; // { int nosys(void); }
- // SYS_NOSYS = 375; // { int nosys(void); }
- // SYS_NOSYS = 376; // { int nosys(void); }
- // SYS_NOSYS = 377; // { int nosys(void); }
- // SYS_NOSYS = 378; // { int nosys(void); }
- // SYS_NOSYS = 379; // { int nosys(void); }
- SYS___MAC_EXECVE = 380 // { int __mac_execve(char *fname, char **argp, char **envp, struct mac *mac_p); }
- SYS___MAC_SYSCALL = 381 // { int __mac_syscall(char *policy, int call, user_addr_t arg); }
- SYS___MAC_GET_FILE = 382 // { int __mac_get_file(char *path_p, struct mac *mac_p); }
- SYS___MAC_SET_FILE = 383 // { int __mac_set_file(char *path_p, struct mac *mac_p); }
- SYS___MAC_GET_LINK = 384 // { int __mac_get_link(char *path_p, struct mac *mac_p); }
- SYS___MAC_SET_LINK = 385 // { int __mac_set_link(char *path_p, struct mac *mac_p); }
- SYS___MAC_GET_PROC = 386 // { int __mac_get_proc(struct mac *mac_p); }
- SYS___MAC_SET_PROC = 387 // { int __mac_set_proc(struct mac *mac_p); }
- SYS___MAC_GET_FD = 388 // { int __mac_get_fd(int fd, struct mac *mac_p); }
- SYS___MAC_SET_FD = 389 // { int __mac_set_fd(int fd, struct mac *mac_p); }
- SYS___MAC_GET_PID = 390 // { int __mac_get_pid(pid_t pid, struct mac *mac_p); }
- SYS___MAC_GET_LCID = 391 // { int __mac_get_lcid(pid_t lcid, struct mac *mac_p); }
- SYS___MAC_GET_LCTX = 392 // { int __mac_get_lctx(struct mac *mac_p); }
- SYS___MAC_SET_LCTX = 393 // { int __mac_set_lctx(struct mac *mac_p); }
- SYS_SETLCID = 394 // { int setlcid(pid_t pid, pid_t lcid) NO_SYSCALL_STUB; }
- SYS_GETLCID = 395 // { int getlcid(pid_t pid) NO_SYSCALL_STUB; }
- SYS_READ_NOCANCEL = 396 // { user_ssize_t read_nocancel(int fd, user_addr_t cbuf, user_size_t nbyte) NO_SYSCALL_STUB; }
- SYS_WRITE_NOCANCEL = 397 // { user_ssize_t write_nocancel(int fd, user_addr_t cbuf, user_size_t nbyte) NO_SYSCALL_STUB; }
- SYS_OPEN_NOCANCEL = 398 // { int open_nocancel(user_addr_t path, int flags, int mode) NO_SYSCALL_STUB; }
- SYS_CLOSE_NOCANCEL = 399 // { int close_nocancel(int fd) NO_SYSCALL_STUB; }
- SYS_WAIT4_NOCANCEL = 400 // { int wait4_nocancel(int pid, user_addr_t status, int options, user_addr_t rusage) NO_SYSCALL_STUB; }
- SYS_RECVMSG_NOCANCEL = 401 // { int recvmsg_nocancel(int s, struct msghdr *msg, int flags) NO_SYSCALL_STUB; }
- SYS_SENDMSG_NOCANCEL = 402 // { int sendmsg_nocancel(int s, caddr_t msg, int flags) NO_SYSCALL_STUB; }
- SYS_RECVFROM_NOCANCEL = 403 // { int recvfrom_nocancel(int s, void *buf, size_t len, int flags, struct sockaddr *from, int *fromlenaddr) NO_SYSCALL_STUB; }
- SYS_ACCEPT_NOCANCEL = 404 // { int accept_nocancel(int s, caddr_t name, socklen_t *anamelen) NO_SYSCALL_STUB; }
- // SYS_NOSYS = 401; // { int nosys(void); }
- // SYS_NOSYS = 402; // { int nosys(void); }
- // SYS_NOSYS = 403; // { int nosys(void); }
- // SYS_NOSYS = 404; // { int nosys(void); }
- SYS_MSYNC_NOCANCEL = 405 // { int msync_nocancel(caddr_t addr, size_t len, int flags) NO_SYSCALL_STUB; }
- SYS_FCNTL_NOCANCEL = 406 // { int fcntl_nocancel(int fd, int cmd, long arg) NO_SYSCALL_STUB; }
- SYS_SELECT_NOCANCEL = 407 // { int select_nocancel(int nd, u_int32_t *in, u_int32_t *ou, u_int32_t *ex, struct timeval *tv) NO_SYSCALL_STUB; }
- SYS_FSYNC_NOCANCEL = 408 // { int fsync_nocancel(int fd) NO_SYSCALL_STUB; }
- SYS_CONNECT_NOCANCEL = 409 // { int connect_nocancel(int s, caddr_t name, socklen_t namelen) NO_SYSCALL_STUB; }
- // SYS_NOSYS = 409; // { int nosys(void); }
- SYS_SIGSUSPEND_NOCANCEL = 410 // { int sigsuspend_nocancel(sigset_t mask) NO_SYSCALL_STUB; }
- SYS_READV_NOCANCEL = 411 // { user_ssize_t readv_nocancel(int fd, struct iovec *iovp, u_int iovcnt) NO_SYSCALL_STUB; }
- SYS_WRITEV_NOCANCEL = 412 // { user_ssize_t writev_nocancel(int fd, struct iovec *iovp, u_int iovcnt) NO_SYSCALL_STUB; }
- SYS_SENDTO_NOCANCEL = 413 // { int sendto_nocancel(int s, caddr_t buf, size_t len, int flags, caddr_t to, socklen_t tolen) NO_SYSCALL_STUB; }
- // SYS_NOSYS = 413; // { int nosys(void); }
- SYS_PREAD_NOCANCEL = 414 // { user_ssize_t pread_nocancel(int fd, user_addr_t buf, user_size_t nbyte, off_t offset) NO_SYSCALL_STUB; }
- SYS_PWRITE_NOCANCEL = 415 // { user_ssize_t pwrite_nocancel(int fd, user_addr_t buf, user_size_t nbyte, off_t offset) NO_SYSCALL_STUB; }
- SYS_WAITID_NOCANCEL = 416 // { int waitid_nocancel(idtype_t idtype, id_t id, siginfo_t *infop, int options) NO_SYSCALL_STUB; }
- SYS_POLL_NOCANCEL = 417 // { int poll_nocancel(struct pollfd *fds, u_int nfds, int timeout) NO_SYSCALL_STUB; }
- SYS_MSGSND_NOCANCEL = 418 // { int msgsnd_nocancel(int msqid, void *msgp, size_t msgsz, int msgflg) NO_SYSCALL_STUB; }
- SYS_MSGRCV_NOCANCEL = 419 // { user_ssize_t msgrcv_nocancel(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg) NO_SYSCALL_STUB; }
- // SYS_NOSYS = 418; // { int nosys(void); }
- // SYS_NOSYS = 419; // { int nosys(void); }
- SYS_SEM_WAIT_NOCANCEL = 420 // { int sem_wait_nocancel(sem_t *sem) NO_SYSCALL_STUB; }
- SYS_AIO_SUSPEND_NOCANCEL = 421 // { int aio_suspend_nocancel(user_addr_t aiocblist, int nent, user_addr_t timeoutp) NO_SYSCALL_STUB; }
- SYS___SIGWAIT_NOCANCEL = 422 // { int __sigwait_nocancel(user_addr_t set, user_addr_t sig) NO_SYSCALL_STUB; }
- SYS___SEMWAIT_SIGNAL_NOCANCEL = 423 // { int __semwait_signal_nocancel(int cond_sem, int mutex_sem, int timeout, int relative, time_t tv_sec, int32_t tv_nsec) NO_SYSCALL_STUB; }
- SYS___MAC_MOUNT = 424 // { int __mac_mount(char *type, char *path, int flags, caddr_t data, struct mac *mac_p); }
- SYS___MAC_GET_MOUNT = 425 // { int __mac_get_mount(char *path, struct mac *mac_p); }
- SYS___MAC_GETFSSTAT = 426 // { int __mac_getfsstat(user_addr_t buf, int bufsize, user_addr_t mac, int macsize, int flags); }
+ SYS_SYSCALL = 0
+ SYS_EXIT = 1
+ SYS_FORK = 2
+ SYS_READ = 3
+ SYS_WRITE = 4
+ SYS_OPEN = 5
+ SYS_CLOSE = 6
+ SYS_WAIT4 = 7
+ SYS_LINK = 9
+ SYS_UNLINK = 10
+ SYS_CHDIR = 12
+ SYS_FCHDIR = 13
+ SYS_MKNOD = 14
+ SYS_CHMOD = 15
+ SYS_CHOWN = 16
+ SYS_GETFSSTAT = 18
+ SYS_GETPID = 20
+ SYS_SETUID = 23
+ SYS_GETUID = 24
+ SYS_GETEUID = 25
+ SYS_PTRACE = 26
+ SYS_RECVMSG = 27
+ SYS_SENDMSG = 28
+ SYS_RECVFROM = 29
+ SYS_ACCEPT = 30
+ SYS_GETPEERNAME = 31
+ SYS_GETSOCKNAME = 32
+ SYS_ACCESS = 33
+ SYS_CHFLAGS = 34
+ SYS_FCHFLAGS = 35
+ SYS_SYNC = 36
+ SYS_KILL = 37
+ SYS_GETPPID = 39
+ SYS_DUP = 41
+ SYS_PIPE = 42
+ SYS_GETEGID = 43
+ SYS_PROFIL = 44
+ SYS_SIGACTION = 46
+ SYS_GETGID = 47
+ SYS_SIGPROCMASK = 48
+ SYS_GETLOGIN = 49
+ SYS_SETLOGIN = 50
+ SYS_ACCT = 51
+ SYS_SIGPENDING = 52
+ SYS_SIGALTSTACK = 53
+ SYS_IOCTL = 54
+ SYS_REBOOT = 55
+ SYS_REVOKE = 56
+ SYS_SYMLINK = 57
+ SYS_READLINK = 58
+ SYS_EXECVE = 59
+ SYS_UMASK = 60
+ SYS_CHROOT = 61
+ SYS_MSYNC = 65
+ SYS_VFORK = 66
+ SYS_MUNMAP = 73
+ SYS_MPROTECT = 74
+ SYS_MADVISE = 75
+ SYS_MINCORE = 78
+ SYS_GETGROUPS = 79
+ SYS_SETGROUPS = 80
+ SYS_GETPGRP = 81
+ SYS_SETPGID = 82
+ SYS_SETITIMER = 83
+ SYS_SWAPON = 85
+ SYS_GETITIMER = 86
+ SYS_GETDTABLESIZE = 89
+ SYS_DUP2 = 90
+ SYS_FCNTL = 92
+ SYS_SELECT = 93
+ SYS_FSYNC = 95
+ SYS_SETPRIORITY = 96
+ SYS_SOCKET = 97
+ SYS_CONNECT = 98
+ SYS_GETPRIORITY = 100
+ SYS_BIND = 104
+ SYS_SETSOCKOPT = 105
+ SYS_LISTEN = 106
+ SYS_SIGSUSPEND = 111
+ SYS_GETTIMEOFDAY = 116
+ SYS_GETRUSAGE = 117
+ SYS_GETSOCKOPT = 118
+ SYS_READV = 120
+ SYS_WRITEV = 121
+ SYS_SETTIMEOFDAY = 122
+ SYS_FCHOWN = 123
+ SYS_FCHMOD = 124
+ SYS_SETREUID = 126
+ SYS_SETREGID = 127
+ SYS_RENAME = 128
+ SYS_FLOCK = 131
+ SYS_MKFIFO = 132
+ SYS_SENDTO = 133
+ SYS_SHUTDOWN = 134
+ SYS_SOCKETPAIR = 135
+ SYS_MKDIR = 136
+ SYS_RMDIR = 137
+ SYS_UTIMES = 138
+ SYS_FUTIMES = 139
+ SYS_ADJTIME = 140
+ SYS_GETHOSTUUID = 142
+ SYS_SETSID = 147
+ SYS_GETPGID = 151
+ SYS_SETPRIVEXEC = 152
+ SYS_PREAD = 153
+ SYS_PWRITE = 154
+ SYS_NFSSVC = 155
+ SYS_STATFS = 157
+ SYS_FSTATFS = 158
+ SYS_UNMOUNT = 159
+ SYS_GETFH = 161
+ SYS_QUOTACTL = 165
+ SYS_MOUNT = 167
+ SYS_CSOPS = 169
+ SYS_WAITID = 173
+ SYS_ADD_PROFIL = 176
+ SYS_KDEBUG_TRACE = 180
+ SYS_SETGID = 181
+ SYS_SETEGID = 182
+ SYS_SETEUID = 183
+ SYS_SIGRETURN = 184
+ SYS_CHUD = 185
+ SYS_FDATASYNC = 187
+ SYS_STAT = 188
+ SYS_FSTAT = 189
+ SYS_LSTAT = 190
+ SYS_PATHCONF = 191
+ SYS_FPATHCONF = 192
+ SYS_GETRLIMIT = 194
+ SYS_SETRLIMIT = 195
+ SYS_GETDIRENTRIES = 196
+ SYS_MMAP = 197
+ SYS_LSEEK = 199
+ SYS_TRUNCATE = 200
+ SYS_FTRUNCATE = 201
+ SYS___SYSCTL = 202
+ SYS_MLOCK = 203
+ SYS_MUNLOCK = 204
+ SYS_UNDELETE = 205
+ SYS_ATSOCKET = 206
+ SYS_ATGETMSG = 207
+ SYS_ATPUTMSG = 208
+ SYS_ATPSNDREQ = 209
+ SYS_ATPSNDRSP = 210
+ SYS_ATPGETREQ = 211
+ SYS_ATPGETRSP = 212
+ SYS_MKCOMPLEX = 216
+ SYS_STATV = 217
+ SYS_LSTATV = 218
+ SYS_FSTATV = 219
+ SYS_GETATTRLIST = 220
+ SYS_SETATTRLIST = 221
+ SYS_GETDIRENTRIESATTR = 222
+ SYS_EXCHANGEDATA = 223
+ SYS_SEARCHFS = 225
+ SYS_DELETE = 226
+ SYS_COPYFILE = 227
+ SYS_FGETATTRLIST = 228
+ SYS_FSETATTRLIST = 229
+ SYS_POLL = 230
+ SYS_WATCHEVENT = 231
+ SYS_WAITEVENT = 232
+ SYS_MODWATCH = 233
+ SYS_GETXATTR = 234
+ SYS_FGETXATTR = 235
+ SYS_SETXATTR = 236
+ SYS_FSETXATTR = 237
+ SYS_REMOVEXATTR = 238
+ SYS_FREMOVEXATTR = 239
+ SYS_LISTXATTR = 240
+ SYS_FLISTXATTR = 241
+ SYS_FSCTL = 242
+ SYS_INITGROUPS = 243
+ SYS_POSIX_SPAWN = 244
+ SYS_FFSCTL = 245
+ SYS_NFSCLNT = 247
+ SYS_FHOPEN = 248
+ SYS_MINHERIT = 250
+ SYS_SEMSYS = 251
+ SYS_MSGSYS = 252
+ SYS_SHMSYS = 253
+ SYS_SEMCTL = 254
+ SYS_SEMGET = 255
+ SYS_SEMOP = 256
+ SYS_MSGCTL = 258
+ SYS_MSGGET = 259
+ SYS_MSGSND = 260
+ SYS_MSGRCV = 261
+ SYS_SHMAT = 262
+ SYS_SHMCTL = 263
+ SYS_SHMDT = 264
+ SYS_SHMGET = 265
+ SYS_SHM_OPEN = 266
+ SYS_SHM_UNLINK = 267
+ SYS_SEM_OPEN = 268
+ SYS_SEM_CLOSE = 269
+ SYS_SEM_UNLINK = 270
+ SYS_SEM_WAIT = 271
+ SYS_SEM_TRYWAIT = 272
+ SYS_SEM_POST = 273
+ SYS_SEM_GETVALUE = 274
+ SYS_SEM_INIT = 275
+ SYS_SEM_DESTROY = 276
+ SYS_OPEN_EXTENDED = 277
+ SYS_UMASK_EXTENDED = 278
+ SYS_STAT_EXTENDED = 279
+ SYS_LSTAT_EXTENDED = 280
+ SYS_FSTAT_EXTENDED = 281
+ SYS_CHMOD_EXTENDED = 282
+ SYS_FCHMOD_EXTENDED = 283
+ SYS_ACCESS_EXTENDED = 284
+ SYS_SETTID = 285
+ SYS_GETTID = 286
+ SYS_SETSGROUPS = 287
+ SYS_GETSGROUPS = 288
+ SYS_SETWGROUPS = 289
+ SYS_GETWGROUPS = 290
+ SYS_MKFIFO_EXTENDED = 291
+ SYS_MKDIR_EXTENDED = 292
+ SYS_IDENTITYSVC = 293
+ SYS_SHARED_REGION_CHECK_NP = 294
+ SYS_SHARED_REGION_MAP_NP = 295
+ SYS_VM_PRESSURE_MONITOR = 296
+ SYS_PSYNCH_RW_LONGRDLOCK = 297
+ SYS_PSYNCH_RW_YIELDWRLOCK = 298
+ SYS_PSYNCH_RW_DOWNGRADE = 299
+ SYS_PSYNCH_RW_UPGRADE = 300
+ SYS_PSYNCH_MUTEXWAIT = 301
+ SYS_PSYNCH_MUTEXDROP = 302
+ SYS_PSYNCH_CVBROAD = 303
+ SYS_PSYNCH_CVSIGNAL = 304
+ SYS_PSYNCH_CVWAIT = 305
+ SYS_PSYNCH_RW_RDLOCK = 306
+ SYS_PSYNCH_RW_WRLOCK = 307
+ SYS_PSYNCH_RW_UNLOCK = 308
+ SYS_PSYNCH_RW_UNLOCK2 = 309
+ SYS_GETSID = 310
+ SYS_SETTID_WITH_PID = 311
+ SYS_AIO_FSYNC = 313
+ SYS_AIO_RETURN = 314
+ SYS_AIO_SUSPEND = 315
+ SYS_AIO_CANCEL = 316
+ SYS_AIO_ERROR = 317
+ SYS_AIO_READ = 318
+ SYS_AIO_WRITE = 319
+ SYS_LIO_LISTIO = 320
+ SYS_IOPOLICYSYS = 322
+ SYS_MLOCKALL = 324
+ SYS_MUNLOCKALL = 325
+ SYS_ISSETUGID = 327
+ SYS___PTHREAD_KILL = 328
+ SYS___PTHREAD_SIGMASK = 329
+ SYS___SIGWAIT = 330
+ SYS___DISABLE_THREADSIGNAL = 331
+ SYS___PTHREAD_MARKCANCEL = 332
+ SYS___PTHREAD_CANCELED = 333
+ SYS___SEMWAIT_SIGNAL = 334
+ SYS_PROC_INFO = 336
+ SYS_SENDFILE = 337
+ SYS_STAT64 = 338
+ SYS_FSTAT64 = 339
+ SYS_LSTAT64 = 340
+ SYS_STAT64_EXTENDED = 341
+ SYS_LSTAT64_EXTENDED = 342
+ SYS_FSTAT64_EXTENDED = 343
+ SYS_GETDIRENTRIES64 = 344
+ SYS_STATFS64 = 345
+ SYS_FSTATFS64 = 346
+ SYS_GETFSSTAT64 = 347
+ SYS___PTHREAD_CHDIR = 348
+ SYS___PTHREAD_FCHDIR = 349
+ SYS_AUDIT = 350
+ SYS_AUDITON = 351
+ SYS_GETAUID = 353
+ SYS_SETAUID = 354
+ SYS_GETAUDIT = 355
+ SYS_SETAUDIT = 356
+ SYS_GETAUDIT_ADDR = 357
+ SYS_SETAUDIT_ADDR = 358
+ SYS_AUDITCTL = 359
+ SYS_BSDTHREAD_CREATE = 360
+ SYS_BSDTHREAD_TERMINATE = 361
+ SYS_KQUEUE = 362
+ SYS_KEVENT = 363
+ SYS_LCHOWN = 364
+ SYS_STACK_SNAPSHOT = 365
+ SYS_BSDTHREAD_REGISTER = 366
+ SYS_WORKQ_OPEN = 367
+ SYS_WORKQ_KERNRETURN = 368
+ SYS_KEVENT64 = 369
+ SYS___OLD_SEMWAIT_SIGNAL = 370
+ SYS___OLD_SEMWAIT_SIGNAL_NOCANCEL = 371
+ SYS_THREAD_SELFID = 372
+ SYS___MAC_EXECVE = 380
+ SYS___MAC_SYSCALL = 381
+ SYS___MAC_GET_FILE = 382
+ SYS___MAC_SET_FILE = 383
+ SYS___MAC_GET_LINK = 384
+ SYS___MAC_SET_LINK = 385
+ SYS___MAC_GET_PROC = 386
+ SYS___MAC_SET_PROC = 387
+ SYS___MAC_GET_FD = 388
+ SYS___MAC_SET_FD = 389
+ SYS___MAC_GET_PID = 390
+ SYS___MAC_GET_LCID = 391
+ SYS___MAC_GET_LCTX = 392
+ SYS___MAC_SET_LCTX = 393
+ SYS_SETLCID = 394
+ SYS_GETLCID = 395
+ SYS_READ_NOCANCEL = 396
+ SYS_WRITE_NOCANCEL = 397
+ SYS_OPEN_NOCANCEL = 398
+ SYS_CLOSE_NOCANCEL = 399
+ SYS_WAIT4_NOCANCEL = 400
+ SYS_RECVMSG_NOCANCEL = 401
+ SYS_SENDMSG_NOCANCEL = 402
+ SYS_RECVFROM_NOCANCEL = 403
+ SYS_ACCEPT_NOCANCEL = 404
+ SYS_MSYNC_NOCANCEL = 405
+ SYS_FCNTL_NOCANCEL = 406
+ SYS_SELECT_NOCANCEL = 407
+ SYS_FSYNC_NOCANCEL = 408
+ SYS_CONNECT_NOCANCEL = 409
+ SYS_SIGSUSPEND_NOCANCEL = 410
+ SYS_READV_NOCANCEL = 411
+ SYS_WRITEV_NOCANCEL = 412
+ SYS_SENDTO_NOCANCEL = 413
+ SYS_PREAD_NOCANCEL = 414
+ SYS_PWRITE_NOCANCEL = 415
+ SYS_WAITID_NOCANCEL = 416
+ SYS_POLL_NOCANCEL = 417
+ SYS_MSGSND_NOCANCEL = 418
+ SYS_MSGRCV_NOCANCEL = 419
+ SYS_SEM_WAIT_NOCANCEL = 420
+ SYS_AIO_SUSPEND_NOCANCEL = 421
+ SYS___SIGWAIT_NOCANCEL = 422
+ SYS___SEMWAIT_SIGNAL_NOCANCEL = 423
+ SYS___MAC_MOUNT = 424
+ SYS___MAC_GET_MOUNT = 425
+ SYS___MAC_GETFSSTAT = 426
+ SYS_FSGETPATH = 427
+ SYS_AUDIT_SESSION_SELF = 428
+ SYS_AUDIT_SESSION_JOIN = 429
+ SYS_PID_SUSPEND = 430
+ SYS_PID_RESUME = 431
+ SYS_FILEPORT_MAKEPORT = 432
+ SYS_FILEPORT_MAKEFD = 433
+ SYS_MAXSYSCALL = 434
)
diff --git a/src/pkg/syscall/ztypes_linux_386.go b/src/pkg/syscall/ztypes_linux_386.go
index 65c8b87db..252fbff74 100644
--- a/src/pkg/syscall/ztypes_linux_386.go
+++ b/src/pkg/syscall/ztypes_linux_386.go
@@ -100,6 +100,8 @@ const (
SizeofIfAddrmsg = 0x8
SizeofRtmsg = 0xc
SizeofRtNexthop = 0x8
+ SizeofSockFilter = 0x8
+ SizeofSockFprog = 0x8
SizeofInotifyEvent = 0x10
)
@@ -400,6 +402,19 @@ type RtNexthop struct {
Ifindex int32
}
+type SockFilter struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
+
+type SockFprog struct {
+ Len uint16
+ Pad_godefs_0 [2]byte
+ Filter *SockFilter
+}
+
type InotifyEvent struct {
Wd int32
Mask uint32
diff --git a/src/pkg/syscall/ztypes_linux_amd64.go b/src/pkg/syscall/ztypes_linux_amd64.go
index e26b6bfd2..520ba963a 100644
--- a/src/pkg/syscall/ztypes_linux_amd64.go
+++ b/src/pkg/syscall/ztypes_linux_amd64.go
@@ -100,6 +100,8 @@ const (
SizeofIfAddrmsg = 0x8
SizeofRtmsg = 0xc
SizeofRtNexthop = 0x8
+ SizeofSockFilter = 0x8
+ SizeofSockFprog = 0x10
SizeofInotifyEvent = 0x10
)
@@ -402,6 +404,19 @@ type RtNexthop struct {
Ifindex int32
}
+type SockFilter struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
+
+type SockFprog struct {
+ Len uint16
+ Pad_godefs_0 [6]byte
+ Filter *SockFilter
+}
+
type InotifyEvent struct {
Wd int32
Mask uint32
diff --git a/src/pkg/syscall/ztypes_linux_arm.go b/src/pkg/syscall/ztypes_linux_arm.go
index ebd5379cb..2421df081 100644
--- a/src/pkg/syscall/ztypes_linux_arm.go
+++ b/src/pkg/syscall/ztypes_linux_arm.go
@@ -105,6 +105,8 @@ const (
SizeofIfAddrmsg = 0x8
SizeofRtmsg = 0xc
SizeofRtNexthop = 0x8
+ SizeofSockFilter = 0x8
+ SizeofSockFprog = 0x8
SizeofInotifyEvent = 0x10
)
@@ -407,6 +409,19 @@ type RtNexthop struct {
Ifindex int32
}
+type SockFilter struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
+
+type SockFprog struct {
+ Len uint16
+ Pad_godefs_0 [2]byte
+ Filter *SockFilter
+}
+
type InotifyEvent struct {
Wd int32
Mask uint32
diff --git a/src/pkg/syscall/ztypes_plan9_386.go b/src/pkg/syscall/ztypes_plan9_386.go
index 8f823ba65..3e3a8d1f3 100644
--- a/src/pkg/syscall/ztypes_plan9_386.go
+++ b/src/pkg/syscall/ztypes_plan9_386.go
@@ -9,6 +9,7 @@ const (
O_RDONLY = 0
O_WRONLY = 0x1
O_RDWR = 0x2
+ O_TRUNC = 0x10
O_CLOEXEC = 0x20
O_EXCL = 0x1000
STATMAX = 0xffff
diff --git a/src/pkg/syscall/ztypes_windows_386.go b/src/pkg/syscall/ztypes_windows_386.go
index b04fea576..6ea85e2b8 100644
--- a/src/pkg/syscall/ztypes_windows_386.go
+++ b/src/pkg/syscall/ztypes_windows_386.go
@@ -23,6 +23,7 @@ const (
ERROR_PATH_NOT_FOUND = 3
ERROR_NO_MORE_FILES = 18
ERROR_BROKEN_PIPE = 109
+ ERROR_BUFFER_OVERFLOW = 111
ERROR_INSUFFICIENT_BUFFER = 122
ERROR_MOD_NOT_FOUND = 126
ERROR_PROC_NOT_FOUND = 127
@@ -347,6 +348,7 @@ type Timezoneinformation struct {
// Socket related.
const (
+ AF_UNSPEC = 0
AF_UNIX = 1
AF_INET = 2
AF_INET6 = 23
@@ -545,3 +547,110 @@ type DNSRecord struct {
Reserved uint32
Data [40]byte
}
+
+const (
+ TF_DISCONNECT = 1
+ TF_REUSE_SOCKET = 2
+ TF_WRITE_BEHIND = 4
+ TF_USE_DEFAULT_WORKER = 0
+ TF_USE_SYSTEM_THREAD = 16
+ TF_USE_KERNEL_APC = 32
+)
+
+type TransmitFileBuffers struct {
+ Head uintptr
+ HeadLength uint32
+ Tail uintptr
+ TailLength uint32
+}
+
+const (
+ IFF_UP = 1
+ IFF_BROADCAST = 2
+ IFF_LOOPBACK = 4
+ IFF_POINTTOPOINT = 8
+ IFF_MULTICAST = 16
+)
+
+const SIO_GET_INTERFACE_LIST = 0x4004747F
+
+// TODO(mattn): SockaddrGen is union of sockaddr/sockaddr_in/sockaddr_in6_old.
+// will be fixed to change variable type as suitable.
+
+type SockaddrGen [24]byte
+
+type InterfaceInfo struct {
+ Flags uint32
+ Address SockaddrGen
+ BroadcastAddress SockaddrGen
+ Netmask SockaddrGen
+}
+
+type IpAddressString struct {
+ String [16]byte
+}
+
+type IpMaskString IpAddressString
+
+type IpAddrString struct {
+ Next *IpAddrString
+ IpAddress IpAddressString
+ IpMask IpMaskString
+ Context uint32
+}
+
+const MAX_ADAPTER_NAME_LENGTH = 256
+const MAX_ADAPTER_DESCRIPTION_LENGTH = 128
+const MAX_ADAPTER_ADDRESS_LENGTH = 8
+
+type IpAdapterInfo struct {
+ Next *IpAdapterInfo
+ ComboIndex uint32
+ AdapterName [MAX_ADAPTER_NAME_LENGTH + 4]byte
+ Description [MAX_ADAPTER_DESCRIPTION_LENGTH + 4]byte
+ AddressLength uint32
+ Address [MAX_ADAPTER_ADDRESS_LENGTH]byte
+ Index uint32
+ Type uint32
+ DhcpEnabled uint32
+ CurrentIpAddress *IpAddrString
+ IpAddressList IpAddrString
+ GatewayList IpAddrString
+ DhcpServer IpAddrString
+ HaveWins bool
+ PrimaryWinsServer IpAddrString
+ SecondaryWinsServer IpAddrString
+ LeaseObtained int64
+ LeaseExpires int64
+}
+
+const MAXLEN_PHYSADDR = 8
+const MAX_INTERFACE_NAME_LEN = 256
+const MAXLEN_IFDESCR = 256
+
+type MibIfRow struct {
+ Name [MAX_INTERFACE_NAME_LEN]uint16
+ Index uint32
+ Type uint32
+ Mtu uint32
+ Speed uint32
+ PhysAddrLen uint32
+ PhysAddr [MAXLEN_PHYSADDR]byte
+ AdminStatus uint32
+ OperStatus uint32
+ LastChange uint32
+ InOctets uint32
+ InUcastPkts uint32
+ InNUcastPkts uint32
+ InDiscards uint32
+ InErrors uint32
+ InUnknownProtos uint32
+ OutOctets uint32
+ OutUcastPkts uint32
+ OutNUcastPkts uint32
+ OutDiscards uint32
+ OutErrors uint32
+ OutQLen uint32
+ DescrLen uint32
+ Descr [MAXLEN_IFDESCR]byte
+}
diff --git a/src/pkg/syslog/syslog_unix.go b/src/pkg/syslog/syslog_unix.go
index fa15e882d..b1516715b 100644
--- a/src/pkg/syslog/syslog_unix.go
+++ b/src/pkg/syslog/syslog_unix.go
@@ -27,5 +27,5 @@ func unixSyslog() (conn serverConn, err os.Error) {
}
}
}
- return nil, os.ErrorString("Unix syslog delivery error")
+ return nil, os.NewError("Unix syslog delivery error")
}
diff --git a/src/pkg/time/Makefile b/src/pkg/time/Makefile
index 3fa96065e..023e8775e 100644
--- a/src/pkg/time/Makefile
+++ b/src/pkg/time/Makefile
@@ -13,17 +13,29 @@ GOFILES=\
time.go\
GOFILES_freebsd=\
+ sys_posix.go\
+ zoneinfo_posix.go\
zoneinfo_unix.go\
GOFILES_darwin=\
+ sys_posix.go\
+ zoneinfo_posix.go\
zoneinfo_unix.go\
GOFILES_linux=\
+ sys_posix.go\
+ zoneinfo_posix.go\
zoneinfo_unix.go\
GOFILES_windows=\
+ sys_posix.go\
zoneinfo_windows.go\
+GOFILES_plan9=\
+ sys_plan9.go\
+ zoneinfo_posix.go\
+ zoneinfo_plan9.go\
+
GOFILES+=$(GOFILES_$(GOOS))
include ../../Make.pkg
diff --git a/src/pkg/time/format.go b/src/pkg/time/format.go
index 47d736342..e0f56129e 100644
--- a/src/pkg/time/format.go
+++ b/src/pkg/time/format.go
@@ -355,7 +355,7 @@ func (t *Time) String() string {
return t.Format(UnixDate)
}
-var errBad = os.ErrorString("bad") // just a marker; not returned to user
+var errBad = os.NewError("bad") // just a marker; not returned to user
// ParseError describes a problem parsing a time string.
type ParseError struct {
diff --git a/src/pkg/time/sys.go b/src/pkg/time/sys.go
index 63f4cbf3d..9fde3b3b6 100644
--- a/src/pkg/time/sys.go
+++ b/src/pkg/time/sys.go
@@ -4,10 +4,7 @@
package time
-import (
- "os"
- "syscall"
-)
+import "os"
// Seconds reports the number of seconds since the Unix epoch,
// January 1, 1970 00:00:00 UTC.
@@ -52,11 +49,3 @@ func sleep(t, ns int64) (int64, os.Error) {
}
return t, nil
}
-
-func sysSleep(t int64) os.Error {
- errno := syscall.Sleep(t)
- if errno != 0 && errno != syscall.EINTR {
- return os.NewSyscallError("sleep", errno)
- }
- return nil
-}
diff --git a/src/pkg/time/sys_plan9.go b/src/pkg/time/sys_plan9.go
new file mode 100644
index 000000000..abe8649a2
--- /dev/null
+++ b/src/pkg/time/sys_plan9.go
@@ -0,0 +1,18 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package time
+
+import (
+ "os"
+ "syscall"
+)
+
+func sysSleep(t int64) os.Error {
+ err := syscall.Sleep(t)
+ if err != nil {
+ return os.NewSyscallError("sleep", err)
+ }
+ return nil
+}
diff --git a/src/pkg/time/sys_posix.go b/src/pkg/time/sys_posix.go
new file mode 100644
index 000000000..0d1eb72fc
--- /dev/null
+++ b/src/pkg/time/sys_posix.go
@@ -0,0 +1,18 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package time
+
+import (
+ "os"
+ "syscall"
+)
+
+func sysSleep(t int64) os.Error {
+ errno := syscall.Sleep(t)
+ if errno != 0 && errno != syscall.EINTR {
+ return os.NewSyscallError("sleep", errno)
+ }
+ return nil
+}
diff --git a/src/pkg/time/tick.go b/src/pkg/time/tick.go
index dde18000d..852bae9c9 100644
--- a/src/pkg/time/tick.go
+++ b/src/pkg/time/tick.go
@@ -160,7 +160,7 @@ var onceStartTickerLoop sync.Once
// ns must be greater than zero; if not, NewTicker will panic.
func NewTicker(ns int64) *Ticker {
if ns <= 0 {
- panic(os.ErrorString("non-positive interval for NewTicker"))
+ panic(os.NewError("non-positive interval for NewTicker"))
}
c := make(chan int64, 1) // See comment on send in tickerLoop
t := &Ticker{
diff --git a/src/pkg/time/zoneinfo_plan9.go b/src/pkg/time/zoneinfo_plan9.go
new file mode 100644
index 000000000..3c3e7c424
--- /dev/null
+++ b/src/pkg/time/zoneinfo_plan9.go
@@ -0,0 +1,59 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Parse Plan 9 timezone(2) files.
+
+package time
+
+import (
+ "os"
+ "strconv"
+ "strings"
+)
+
+func parseZones(s string) (zt []zonetime) {
+ f := strings.Fields(s)
+ if len(f) < 4 {
+ return
+ }
+
+ // standard timezone offset
+ o, err := strconv.Atoi(f[1])
+ if err != nil {
+ return
+ }
+ std := &zone{name: f[0], utcoff: o, isdst: false}
+
+ // alternate timezone offset
+ o, err = strconv.Atoi(f[3])
+ if err != nil {
+ return
+ }
+ dst := &zone{name: f[2], utcoff: o, isdst: true}
+
+ // transition time pairs
+ f = f[4:]
+ for i := 0; i < len(f); i++ {
+ z := std
+ if i%2 == 0 {
+ z = dst
+ }
+ t, err := strconv.Atoi(f[i])
+ if err != nil {
+ return nil
+ }
+ t -= std.utcoff
+ zt = append(zt, zonetime{time: int32(t), zone: z})
+ }
+ return
+}
+
+func setupZone() {
+ t, err := os.Getenverror("timezone")
+ if err != nil {
+ // do nothing: use UTC
+ return
+ }
+ zones = parseZones(t)
+}
diff --git a/src/pkg/time/zoneinfo_posix.go b/src/pkg/time/zoneinfo_posix.go
new file mode 100644
index 000000000..b49216410
--- /dev/null
+++ b/src/pkg/time/zoneinfo_posix.go
@@ -0,0 +1,62 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package time
+
+import "sync"
+
+// Parsed representation
+type zone struct {
+ utcoff int
+ isdst bool
+ name string
+}
+
+type zonetime struct {
+ time int32 // transition time, in seconds since 1970 GMT
+ zone *zone // the zone that goes into effect at that time
+ isstd, isutc bool // ignored - no idea what these mean
+}
+
+var zones []zonetime
+var onceSetupZone sync.Once
+
+// Look up the correct time zone (daylight savings or not) for the given unix time, in the current location.
+func lookupTimezone(sec int64) (zone string, offset int) {
+ onceSetupZone.Do(setupZone)
+ if len(zones) == 0 {
+ return "UTC", 0
+ }
+
+ // Binary search for entry with largest time <= sec
+ tz := zones
+ for len(tz) > 1 {
+ m := len(tz) / 2
+ if sec < int64(tz[m].time) {
+ tz = tz[0:m]
+ } else {
+ tz = tz[m:]
+ }
+ }
+ z := tz[0].zone
+ return z.name, z.utcoff
+}
+
+// lookupByName returns the time offset for the
+// time zone with the given abbreviation. It only considers
+// time zones that apply to the current system.
+// For example, for a system configured as being in New York,
+// it only recognizes "EST" and "EDT".
+// For a system in San Francisco, "PST" and "PDT".
+// For a system in Sydney, "EST" and "EDT", though they have
+// different meanings than they do in New York.
+func lookupByName(name string) (off int, found bool) {
+ onceSetupZone.Do(setupZone)
+ for _, z := range zones {
+ if name == z.zone.name {
+ return z.zone.utcoff, true
+ }
+ }
+ return 0, false
+}
diff --git a/src/pkg/time/zoneinfo_unix.go b/src/pkg/time/zoneinfo_unix.go
index 42659ed60..2a83e0c16 100644
--- a/src/pkg/time/zoneinfo_unix.go
+++ b/src/pkg/time/zoneinfo_unix.go
@@ -12,7 +12,6 @@ package time
import (
"io/ioutil"
"os"
- "sync"
)
const (
@@ -66,19 +65,6 @@ func byteString(p []byte) string {
return string(p)
}
-// Parsed representation
-type zone struct {
- utcoff int
- isdst bool
- name string
-}
-
-type zonetime struct {
- time int32 // transition time, in seconds since 1970 GMT
- zone *zone // the zone that goes into effect at that time
- isstd, isutc bool // ignored - no idea what these mean
-}
-
func parseinfo(bytes []byte) (zt []zonetime, ok bool) {
d := data{bytes, false}
@@ -201,9 +187,6 @@ func readinfofile(name string) ([]zonetime, bool) {
return parseinfo(buf)
}
-var zones []zonetime
-var onceSetupZone sync.Once
-
func setupZone() {
// consult $TZ to find the time zone to use.
// no $TZ means use the system default /etc/localtime.
@@ -230,42 +213,3 @@ func setupZone() {
// do nothing: use UTC
}
}
-
-// Look up the correct time zone (daylight savings or not) for the given unix time, in the current location.
-func lookupTimezone(sec int64) (zone string, offset int) {
- onceSetupZone.Do(setupZone)
- if len(zones) == 0 {
- return "UTC", 0
- }
-
- // Binary search for entry with largest time <= sec
- tz := zones
- for len(tz) > 1 {
- m := len(tz) / 2
- if sec < int64(tz[m].time) {
- tz = tz[0:m]
- } else {
- tz = tz[m:]
- }
- }
- z := tz[0].zone
- return z.name, z.utcoff
-}
-
-// lookupByName returns the time offset for the
-// time zone with the given abbreviation. It only considers
-// time zones that apply to the current system.
-// For example, for a system configured as being in New York,
-// it only recognizes "EST" and "EDT".
-// For a system in San Francisco, "PST" and "PDT".
-// For a system in Sydney, "EST" and "EDT", though they have
-// different meanings than they do in New York.
-func lookupByName(name string) (off int, found bool) {
- onceSetupZone.Do(setupZone)
- for _, z := range zones {
- if name == z.zone.name {
- return z.zone.utcoff, true
- }
- }
- return 0, false
-}
diff --git a/src/pkg/unicode/letter.go b/src/pkg/unicode/letter.go
index a0c55bbf7..dbd8638ea 100644
--- a/src/pkg/unicode/letter.go
+++ b/src/pkg/unicode/letter.go
@@ -275,3 +275,52 @@ func (special SpecialCase) ToLower(rune int) int {
}
return r
}
+
+// caseOrbit is defined in tables.go as []foldPair. Right now all the
+// entries fit in uint16, so use uint16. If that changes, compilation
+// will fail (the constants in the composite literal will not fit in uint16)
+// and the types here can change to uint32.
+type foldPair struct {
+ From uint16
+ To uint16
+}
+
+// SimpleFold iterates over Unicode code points equivalent under
+// the Unicode-defined simple case folding. Among the code points
+// equivalent to rune (including rune itself), SimpleFold returns the
+// smallest r >= rune if one exists, or else the smallest r >= 0.
+//
+// For example:
+// SimpleFold('A') = 'a'
+// SimpleFold('a') = 'A'
+//
+// SimpleFold('K') = 'k'
+// SimpleFold('k') = '\u212A' (Kelvin symbol, K)
+// SimpleFold('\u212A') = 'K'
+//
+// SimpleFold('1') = '1'
+//
+func SimpleFold(rune int) int {
+ // Consult caseOrbit table for special cases.
+ lo := 0
+ hi := len(caseOrbit)
+ for lo < hi {
+ m := lo + (hi-lo)/2
+ if int(caseOrbit[m].From) < rune {
+ lo = m + 1
+ } else {
+ hi = m
+ }
+ }
+ if lo < len(caseOrbit) && int(caseOrbit[lo].From) == rune {
+ return int(caseOrbit[lo].To)
+ }
+
+ // No folding specified. This is a one- or two-element
+ // equivalence class containing rune and ToLower(rune)
+ // and ToUpper(rune) if they are different from rune.
+ if l := ToLower(rune); l != rune {
+ return l
+ }
+ return ToUpper(rune)
+}
diff --git a/src/pkg/unicode/letter_test.go b/src/pkg/unicode/letter_test.go
index 4c24ffc51..c4e26df58 100644
--- a/src/pkg/unicode/letter_test.go
+++ b/src/pkg/unicode/letter_test.go
@@ -376,3 +376,49 @@ func TestTurkishCase(t *testing.T) {
}
}
}
+
+var simpleFoldTests = []string{
+ // SimpleFold could order its returned slices in any order it wants,
+ // but we know it orders them in increasing order starting at in
+ // and looping around from MaxRune to 0.
+
+ // Easy cases.
+ "Aa",
+ "aA",
+ "δΔ",
+ "Δδ",
+
+ // ASCII special cases.
+ "KkK",
+ "kKK",
+ "KKk",
+ "Ssſ",
+ "sſS",
+ "ſSs",
+
+ // Non-ASCII special cases.
+ "ρϱΡ",
+ "ϱΡρ",
+ "Ρρϱ",
+ "ͅΙιι",
+ "Ιιιͅ",
+ "ιιͅΙ",
+ "ιͅΙι",
+
+ // Extra special cases: has lower/upper but no case fold.
+ "İ",
+ "ı",
+}
+
+func TestSimpleFold(t *testing.T) {
+ for _, tt := range simpleFoldTests {
+ cycle := []int(tt)
+ rune := cycle[len(cycle)-1]
+ for _, out := range cycle {
+ if r := SimpleFold(rune); r != out {
+ t.Errorf("SimpleFold(%#U) = %#U, want %#U", rune, r, out)
+ }
+ rune = out
+ }
+ }
+}
diff --git a/src/pkg/unicode/maketables.go b/src/pkg/unicode/maketables.go
index 655fe46e4..421d29455 100644
--- a/src/pkg/unicode/maketables.go
+++ b/src/pkg/unicode/maketables.go
@@ -24,15 +24,18 @@ import (
func main() {
flag.Parse()
loadChars() // always needed
+ loadCasefold()
printCategories()
printScriptOrProperty(false)
printScriptOrProperty(true)
printCases()
printLatinProperties()
+ printCasefold()
printSizes()
}
var dataURL = flag.String("data", "", "full URL for UnicodeData.txt; defaults to --url/UnicodeData.txt")
+var casefoldingURL = flag.String("casefolding", "", "full URL for CaseFolding.txt; defaults to --url/CaseFolding.txt")
var url = flag.String("url",
"http://www.unicode.org/Public/6.0.0/ucd/",
"URL of Unicode database directory")
@@ -119,6 +122,8 @@ type Char struct {
upperCase int
lowerCase int
titleCase int
+ foldCase int // simple case folding
+ caseOrbit int // next in simple case folding orbit
}
// Scripts.txt has form:
@@ -308,8 +313,53 @@ func loadChars() {
resp.Body.Close()
}
+func loadCasefold() {
+ if *casefoldingURL == "" {
+ flag.Set("casefolding", *url+"CaseFolding.txt")
+ }
+ resp, err := http.Get(*casefoldingURL)
+ if err != nil {
+ logger.Fatal(err)
+ }
+ if resp.StatusCode != 200 {
+ logger.Fatal("bad GET status for CaseFolding.txt", resp.Status)
+ }
+ input := bufio.NewReader(resp.Body)
+ for {
+ line, err := input.ReadString('\n')
+ if err != nil {
+ if err == os.EOF {
+ break
+ }
+ logger.Fatal(err)
+ }
+ if line[0] == '#' {
+ continue
+ }
+ field := strings.Split(line, "; ", -1)
+ if len(field) != 4 {
+ logger.Fatalf("CaseFolding.txt %.5s...: %d fields (expected %d)\n", line, len(field), 4)
+ }
+ kind := field[1]
+ if kind != "C" && kind != "S" {
+ // Only care about 'common' and 'simple' foldings.
+ continue
+ }
+ p1, err := strconv.Btoui64(field[0], 16)
+ if err != nil {
+ logger.Fatalf("CaseFolding.txt %.5s...: %s", line, err)
+ }
+ p2, err := strconv.Btoui64(field[2], 16)
+ if err != nil {
+ logger.Fatalf("CaseFolding.txt %.5s...: %s", line, err)
+ }
+ chars[p1].foldCase = int(p2)
+ }
+ resp.Body.Close()
+}
+
const progHeader = `// Generated by running
-// maketables --tables=%s --data=%s
+// maketables --tables=%s --data=%s --casefolding=%s
// DO NOT EDIT
package unicode
@@ -330,7 +380,7 @@ func printCategories() {
fullCategoryTest(list)
return
}
- fmt.Printf(progHeader, *tablelist, *dataURL)
+ fmt.Printf(progHeader, *tablelist, *dataURL, *casefoldingURL)
fmt.Println("// Version is the Unicode edition from which the tables are derived.")
fmt.Printf("const Version = %q\n\n", version())
@@ -344,7 +394,7 @@ func printCategories() {
fmt.Print("}\n\n")
}
- decl := make(sort.StringArray, len(list))
+ decl := make(sort.StringSlice, len(list))
ndecl := 0
for _, name := range list {
if _, ok := category[name]; !ok {
@@ -665,7 +715,7 @@ func printScriptOrProperty(doProps bool) {
fmt.Print("}\n\n")
}
- decl := make(sort.StringArray, len(list))
+ decl := make(sort.StringSlice, len(list))
ndecl := 0
for _, name := range list {
if doProps {
@@ -837,13 +887,13 @@ func printCases() {
}
fmt.Printf(
"// Generated by running\n"+
- "// maketables --data=%s\n"+
+ "// maketables --data=%s --casefolding=%s\n"+
"// DO NOT EDIT\n\n"+
"// CaseRanges is the table describing case mappings for all letters with\n"+
"// non-self mappings.\n"+
"var CaseRanges = _CaseRanges\n"+
"var _CaseRanges = []CaseRange {\n",
- *dataURL)
+ *dataURL, *casefoldingURL)
var startState *caseState // the start of a run; nil for not active
var prevState = &caseState{} // the state of the previous character
@@ -946,13 +996,246 @@ func printLatinProperties() {
if code == ' ' {
property = "pZ | pp"
}
- fmt.Printf("\t0x%.2X: %s, // %q\n", code, property, code)
+ fmt.Printf("\t0x%02X: %s, // %q\n", code, property, code)
+ }
+ fmt.Printf("}\n\n")
+}
+
+func printCasefold() {
+ // Build list of case-folding groups attached to each canonical folded char (typically lower case).
+ var caseOrbit = make([][]int, MaxChar+1)
+ for i := range chars {
+ c := &chars[i]
+ if c.foldCase == 0 {
+ continue
+ }
+ orb := caseOrbit[c.foldCase]
+ if orb == nil {
+ orb = append(orb, c.foldCase)
+ }
+ caseOrbit[c.foldCase] = append(orb, i)
+ }
+
+ // Insert explicit 1-element groups when assuming [lower, upper] would be wrong.
+ for i := range chars {
+ c := &chars[i]
+ f := c.foldCase
+ if f == 0 {
+ f = i
+ }
+ orb := caseOrbit[f]
+ if orb == nil && (c.upperCase != 0 && c.upperCase != i || c.lowerCase != 0 && c.lowerCase != i) {
+ // Default assumption of [upper, lower] is wrong.
+ caseOrbit[i] = []int{i}
+ }
+ }
+
+ // Delete the groups for which assuming [lower, upper] is right.
+ for i, orb := range caseOrbit {
+ if len(orb) == 2 && chars[orb[0]].upperCase == orb[1] && chars[orb[1]].lowerCase == orb[0] {
+ caseOrbit[i] = nil
+ }
+ }
+
+ // Record orbit information in chars.
+ for _, orb := range caseOrbit {
+ if orb == nil {
+ continue
+ }
+ sort.SortInts(orb)
+ c := orb[len(orb)-1]
+ for _, d := range orb {
+ chars[c].caseOrbit = d
+ c = d
+ }
+ }
+
+ printCaseOrbit()
+
+ // Tables of category and script folding exceptions: code points
+ // that must be added when interpreting a particular category/script
+ // in a case-folding context.
+ cat := make(map[string]map[int]bool)
+ for name := range category {
+ if x := foldExceptions(inCategory(name)); len(x) > 0 {
+ cat[name] = x
+ }
+ }
+
+ scr := make(map[string]map[int]bool)
+ for name := range scripts {
+ if x := foldExceptions(inScript(name)); len(x) > 0 {
+ cat[name] = x
+ }
+ }
+
+ printCatFold("FoldCategory", cat)
+ printCatFold("FoldScript", scr)
+}
+
+// inCategory returns a list of all the runes in the category.
+func inCategory(name string) []int {
+ var x []int
+ for i := range chars {
+ c := &chars[i]
+ if c.category == name || len(name) == 1 && len(c.category) > 1 && c.category[0] == name[0] {
+ x = append(x, i)
+ }
}
- fmt.Println("}")
+ return x
}
-var range16Count = 0 // Number of entries in the 16-bit range tables.
-var range32Count = 0 // Number of entries in the 32-bit range tables.
+// inScript returns a list of all the runes in the script.
+func inScript(name string) []int {
+ var x []int
+ for _, s := range scripts[name] {
+ for c := s.lo; c <= s.hi; c++ {
+ x = append(x, int(c))
+ }
+ }
+ return x
+}
+
+// foldExceptions returns a list of all the runes fold-equivalent
+// to runes in class but not in class themselves.
+func foldExceptions(class []int) map[int]bool {
+ // Create map containing class and all fold-equivalent chars.
+ m := make(map[int]bool)
+ for _, r := range class {
+ c := &chars[r]
+ if c.caseOrbit == 0 {
+ // Just upper and lower.
+ if u := c.upperCase; u != 0 {
+ m[u] = true
+ }
+ if l := c.lowerCase; l != 0 {
+ m[l] = true
+ }
+ m[r] = true
+ continue
+ }
+ // Otherwise walk orbit.
+ r0 := r
+ for {
+ m[r] = true
+ r = chars[r].caseOrbit
+ if r == r0 {
+ break
+ }
+ }
+ }
+
+ // Remove class itself.
+ for _, r := range class {
+ m[r] = false, false
+ }
+
+ // What's left is the exceptions.
+ return m
+}
+
+var comment = map[string]string{
+ "FoldCategory": "// FoldCategory maps a category name to a table of\n" +
+ "// code points outside the category that are equivalent under\n" +
+ "// simple case folding to code points inside the category.\n" +
+ "// If there is no entry for a category name, there are no such points.\n",
+
+ "FoldScript": "// FoldScript maps a script name to a table of\n" +
+ "// code points outside the script that are equivalent under\n" +
+ "// simple case folding to code points inside the script.\n" +
+ "// If there is no entry for a script name, there are no such points.\n",
+}
+
+func printCaseOrbit() {
+ if *test {
+ for i := range chars {
+ c := &chars[i]
+ f := c.caseOrbit
+ if f == 0 {
+ if c.lowerCase != i && c.lowerCase != 0 {
+ f = c.lowerCase
+ } else if c.upperCase != i && c.upperCase != 0 {
+ f = c.upperCase
+ } else {
+ f = i
+ }
+ }
+ if g := unicode.SimpleFold(i); g != f {
+ fmt.Fprintf(os.Stderr, "unicode.SimpleFold(%#U) = %#U, want %#U\n", i, g, f)
+ }
+ }
+ return
+ }
+
+ fmt.Printf("var caseOrbit = []foldPair{\n")
+ for i := range chars {
+ c := &chars[i]
+ if c.caseOrbit != 0 {
+ fmt.Printf("\t{0x%04X, 0x%04X},\n", i, c.caseOrbit)
+ foldPairCount++
+ }
+ }
+ fmt.Printf("}\n\n")
+}
+
+func printCatFold(name string, m map[string]map[int]bool) {
+ if *test {
+ var pkgMap map[string]*unicode.RangeTable
+ if name == "FoldCategory" {
+ pkgMap = unicode.FoldCategory
+ } else {
+ pkgMap = unicode.FoldScript
+ }
+ if len(pkgMap) != len(m) {
+ fmt.Fprintf(os.Stderr, "unicode.%s has %d elements, want %d\n", name, len(pkgMap), len(m))
+ return
+ }
+ for k, v := range m {
+ t, ok := pkgMap[k]
+ if !ok {
+ fmt.Fprintf(os.Stderr, "unicode.%s[%q] missing\n", name, k)
+ continue
+ }
+ n := 0
+ for _, r := range t.R16 {
+ for c := int(r.Lo); c <= int(r.Hi); c += int(r.Stride) {
+ if !v[c] {
+ fmt.Fprintf(os.Stderr, "unicode.%s[%q] contains %#U, should not\n", name, k, c)
+ }
+ n++
+ }
+ }
+ for _, r := range t.R32 {
+ for c := int(r.Lo); c <= int(r.Hi); c += int(r.Stride) {
+ if !v[c] {
+ fmt.Fprintf(os.Stderr, "unicode.%s[%q] contains %#U, should not\n", name, k, c)
+ }
+ n++
+ }
+ }
+ if n != len(v) {
+ fmt.Fprintf(os.Stderr, "unicode.%s[%q] has %d code points, want %d\n", name, k, n, len(v))
+ }
+ }
+ return
+ }
+
+ fmt.Print(comment[name])
+ fmt.Printf("var %s = map[string]*RangeTable{\n", name)
+ for name := range m {
+ fmt.Printf("\t%q: fold%s,\n", name, name)
+ }
+ fmt.Printf("}\n\n")
+ for name, class := range m {
+ dumpRange(
+ fmt.Sprintf("var fold%s = &RangeTable{\n", name),
+ func(code int) bool { return class[code] })
+ }
+}
+
+var range16Count = 0 // Number of entries in the 16-bit range tables.
+var range32Count = 0 // Number of entries in the 32-bit range tables.
+var foldPairCount = 0 // Number of fold pairs in the exception tables.
func printSizes() {
if *test {
@@ -963,4 +1246,6 @@ func printSizes() {
range16Bytes := range16Count * 3 * 2
range32Bytes := range32Count * 3 * 4
fmt.Printf("// Range bytes: %d 16-bit, %d 32-bit, %d total.\n", range16Bytes, range32Bytes, range16Bytes+range32Bytes)
+ fmt.Println()
+ fmt.Printf("// Fold orbit bytes: %d pairs, %d bytes\n", foldPairCount, foldPairCount*2*2)
}
diff --git a/src/pkg/unicode/tables.go b/src/pkg/unicode/tables.go
index 32681a8c0..a75011adb 100644
--- a/src/pkg/unicode/tables.go
+++ b/src/pkg/unicode/tables.go
@@ -1,5 +1,5 @@
// Generated by running
-// maketables --tables=all --data=http://www.unicode.org/Public/6.0.0/ucd/UnicodeData.txt
+// maketables --tables=all --data=http://www.unicode.org/Public/6.0.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/6.0.0/ucd/CaseFolding.txt
// DO NOT EDIT
package unicode
@@ -5150,7 +5150,7 @@ var (
)
// Generated by running
-// maketables --data=http://www.unicode.org/Public/6.0.0/ucd/UnicodeData.txt
+// maketables --data=http://www.unicode.org/Public/6.0.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/6.0.0/ucd/CaseFolding.txt
// DO NOT EDIT
// CaseRanges is the table describing case mappings for all letters with
@@ -5539,7 +5539,7 @@ var properties = [MaxLatin1 + 1]uint8{
0x7C: pS | pp, // '|'
0x7D: pP | pp, // '}'
0x7E: pS | pp, // '~'
- 0x7F: pC, // '\x7f'
+ 0x7F: pC, // '\u007f'
0x80: pC, // '\u0080'
0x81: pC, // '\u0081'
0x82: pC, // '\u0082'
@@ -5573,102 +5573,534 @@ var properties = [MaxLatin1 + 1]uint8{
0x9E: pC, // '\u009e'
0x9F: pC, // '\u009f'
0xA0: pZ, // '\u00a0'
- 0xA1: pP | pp, // '\u00a1'
- 0xA2: pS | pp, // '\u00a2'
- 0xA3: pS | pp, // '\u00a3'
- 0xA4: pS | pp, // '\u00a4'
- 0xA5: pS | pp, // '\u00a5'
- 0xA6: pS | pp, // '\u00a6'
- 0xA7: pS | pp, // '\u00a7'
- 0xA8: pS | pp, // '\u00a8'
- 0xA9: pS | pp, // '\u00a9'
- 0xAA: pLl | pp, // '\u00aa'
- 0xAB: pP | pp, // '\u00ab'
- 0xAC: pS | pp, // '\u00ac'
+ 0xA1: pP | pp, // '¡'
+ 0xA2: pS | pp, // '¢'
+ 0xA3: pS | pp, // '£'
+ 0xA4: pS | pp, // '¤'
+ 0xA5: pS | pp, // '¥'
+ 0xA6: pS | pp, // '¦'
+ 0xA7: pS | pp, // '§'
+ 0xA8: pS | pp, // '¨'
+ 0xA9: pS | pp, // '©'
+ 0xAA: pLl | pp, // 'ª'
+ 0xAB: pP | pp, // '«'
+ 0xAC: pS | pp, // '¬'
0xAD: 0, // '\u00ad'
- 0xAE: pS | pp, // '\u00ae'
- 0xAF: pS | pp, // '\u00af'
- 0xB0: pS | pp, // '\u00b0'
- 0xB1: pS | pp, // '\u00b1'
- 0xB2: pN | pp, // '\u00b2'
- 0xB3: pN | pp, // '\u00b3'
- 0xB4: pS | pp, // '\u00b4'
- 0xB5: pLl | pp, // '\u00b5'
- 0xB6: pS | pp, // '\u00b6'
- 0xB7: pP | pp, // '\u00b7'
- 0xB8: pS | pp, // '\u00b8'
- 0xB9: pN | pp, // '\u00b9'
- 0xBA: pLl | pp, // '\u00ba'
- 0xBB: pP | pp, // '\u00bb'
- 0xBC: pN | pp, // '\u00bc'
- 0xBD: pN | pp, // '\u00bd'
- 0xBE: pN | pp, // '\u00be'
- 0xBF: pP | pp, // '\u00bf'
- 0xC0: pLu | pp, // '\u00c0'
- 0xC1: pLu | pp, // '\u00c1'
- 0xC2: pLu | pp, // '\u00c2'
- 0xC3: pLu | pp, // '\u00c3'
- 0xC4: pLu | pp, // '\u00c4'
- 0xC5: pLu | pp, // '\u00c5'
- 0xC6: pLu | pp, // '\u00c6'
- 0xC7: pLu | pp, // '\u00c7'
- 0xC8: pLu | pp, // '\u00c8'
- 0xC9: pLu | pp, // '\u00c9'
- 0xCA: pLu | pp, // '\u00ca'
- 0xCB: pLu | pp, // '\u00cb'
- 0xCC: pLu | pp, // '\u00cc'
- 0xCD: pLu | pp, // '\u00cd'
- 0xCE: pLu | pp, // '\u00ce'
- 0xCF: pLu | pp, // '\u00cf'
- 0xD0: pLu | pp, // '\u00d0'
- 0xD1: pLu | pp, // '\u00d1'
- 0xD2: pLu | pp, // '\u00d2'
- 0xD3: pLu | pp, // '\u00d3'
- 0xD4: pLu | pp, // '\u00d4'
- 0xD5: pLu | pp, // '\u00d5'
- 0xD6: pLu | pp, // '\u00d6'
- 0xD7: pS | pp, // '\u00d7'
- 0xD8: pLu | pp, // '\u00d8'
- 0xD9: pLu | pp, // '\u00d9'
- 0xDA: pLu | pp, // '\u00da'
- 0xDB: pLu | pp, // '\u00db'
- 0xDC: pLu | pp, // '\u00dc'
- 0xDD: pLu | pp, // '\u00dd'
- 0xDE: pLu | pp, // '\u00de'
- 0xDF: pLl | pp, // '\u00df'
- 0xE0: pLl | pp, // '\u00e0'
- 0xE1: pLl | pp, // '\u00e1'
- 0xE2: pLl | pp, // '\u00e2'
- 0xE3: pLl | pp, // '\u00e3'
- 0xE4: pLl | pp, // '\u00e4'
- 0xE5: pLl | pp, // '\u00e5'
- 0xE6: pLl | pp, // '\u00e6'
- 0xE7: pLl | pp, // '\u00e7'
- 0xE8: pLl | pp, // '\u00e8'
- 0xE9: pLl | pp, // '\u00e9'
- 0xEA: pLl | pp, // '\u00ea'
- 0xEB: pLl | pp, // '\u00eb'
- 0xEC: pLl | pp, // '\u00ec'
- 0xED: pLl | pp, // '\u00ed'
- 0xEE: pLl | pp, // '\u00ee'
- 0xEF: pLl | pp, // '\u00ef'
- 0xF0: pLl | pp, // '\u00f0'
- 0xF1: pLl | pp, // '\u00f1'
- 0xF2: pLl | pp, // '\u00f2'
- 0xF3: pLl | pp, // '\u00f3'
- 0xF4: pLl | pp, // '\u00f4'
- 0xF5: pLl | pp, // '\u00f5'
- 0xF6: pLl | pp, // '\u00f6'
- 0xF7: pS | pp, // '\u00f7'
- 0xF8: pLl | pp, // '\u00f8'
- 0xF9: pLl | pp, // '\u00f9'
- 0xFA: pLl | pp, // '\u00fa'
- 0xFB: pLl | pp, // '\u00fb'
- 0xFC: pLl | pp, // '\u00fc'
- 0xFD: pLl | pp, // '\u00fd'
- 0xFE: pLl | pp, // '\u00fe'
- 0xFF: pLl | pp, // '\u00ff'
-}
-
-// Range entries: 3190 16-bit, 657 32-bit, 3847 total.
-// Range bytes: 19140 16-bit, 7884 32-bit, 27024 total.
+ 0xAE: pS | pp, // '®'
+ 0xAF: pS | pp, // '¯'
+ 0xB0: pS | pp, // '°'
+ 0xB1: pS | pp, // '±'
+ 0xB2: pN | pp, // '²'
+ 0xB3: pN | pp, // '³'
+ 0xB4: pS | pp, // '´'
+ 0xB5: pLl | pp, // 'µ'
+ 0xB6: pS | pp, // '¶'
+ 0xB7: pP | pp, // '·'
+ 0xB8: pS | pp, // '¸'
+ 0xB9: pN | pp, // '¹'
+ 0xBA: pLl | pp, // 'º'
+ 0xBB: pP | pp, // '»'
+ 0xBC: pN | pp, // '¼'
+ 0xBD: pN | pp, // '½'
+ 0xBE: pN | pp, // '¾'
+ 0xBF: pP | pp, // '¿'
+ 0xC0: pLu | pp, // 'À'
+ 0xC1: pLu | pp, // 'Á'
+ 0xC2: pLu | pp, // 'Â'
+ 0xC3: pLu | pp, // 'Ã'
+ 0xC4: pLu | pp, // 'Ä'
+ 0xC5: pLu | pp, // 'Å'
+ 0xC6: pLu | pp, // 'Æ'
+ 0xC7: pLu | pp, // 'Ç'
+ 0xC8: pLu | pp, // 'È'
+ 0xC9: pLu | pp, // 'É'
+ 0xCA: pLu | pp, // 'Ê'
+ 0xCB: pLu | pp, // 'Ë'
+ 0xCC: pLu | pp, // 'Ì'
+ 0xCD: pLu | pp, // 'Í'
+ 0xCE: pLu | pp, // 'Î'
+ 0xCF: pLu | pp, // 'Ï'
+ 0xD0: pLu | pp, // 'Ð'
+ 0xD1: pLu | pp, // 'Ñ'
+ 0xD2: pLu | pp, // 'Ò'
+ 0xD3: pLu | pp, // 'Ó'
+ 0xD4: pLu | pp, // 'Ô'
+ 0xD5: pLu | pp, // 'Õ'
+ 0xD6: pLu | pp, // 'Ö'
+ 0xD7: pS | pp, // '×'
+ 0xD8: pLu | pp, // 'Ø'
+ 0xD9: pLu | pp, // 'Ù'
+ 0xDA: pLu | pp, // 'Ú'
+ 0xDB: pLu | pp, // 'Û'
+ 0xDC: pLu | pp, // 'Ü'
+ 0xDD: pLu | pp, // 'Ý'
+ 0xDE: pLu | pp, // 'Þ'
+ 0xDF: pLl | pp, // 'ß'
+ 0xE0: pLl | pp, // 'à'
+ 0xE1: pLl | pp, // 'á'
+ 0xE2: pLl | pp, // 'â'
+ 0xE3: pLl | pp, // 'ã'
+ 0xE4: pLl | pp, // 'ä'
+ 0xE5: pLl | pp, // 'å'
+ 0xE6: pLl | pp, // 'æ'
+ 0xE7: pLl | pp, // 'ç'
+ 0xE8: pLl | pp, // 'è'
+ 0xE9: pLl | pp, // 'é'
+ 0xEA: pLl | pp, // 'ê'
+ 0xEB: pLl | pp, // 'ë'
+ 0xEC: pLl | pp, // 'ì'
+ 0xED: pLl | pp, // 'í'
+ 0xEE: pLl | pp, // 'î'
+ 0xEF: pLl | pp, // 'ï'
+ 0xF0: pLl | pp, // 'ð'
+ 0xF1: pLl | pp, // 'ñ'
+ 0xF2: pLl | pp, // 'ò'
+ 0xF3: pLl | pp, // 'ó'
+ 0xF4: pLl | pp, // 'ô'
+ 0xF5: pLl | pp, // 'õ'
+ 0xF6: pLl | pp, // 'ö'
+ 0xF7: pS | pp, // '÷'
+ 0xF8: pLl | pp, // 'ø'
+ 0xF9: pLl | pp, // 'ù'
+ 0xFA: pLl | pp, // 'ú'
+ 0xFB: pLl | pp, // 'û'
+ 0xFC: pLl | pp, // 'ü'
+ 0xFD: pLl | pp, // 'ý'
+ 0xFE: pLl | pp, // 'þ'
+ 0xFF: pLl | pp, // 'ÿ'
+}
+
+var caseOrbit = []foldPair{
+ {0x004B, 0x006B},
+ {0x0053, 0x0073},
+ {0x006B, 0x212A},
+ {0x0073, 0x017F},
+ {0x00B5, 0x039C},
+ {0x00C5, 0x00E5},
+ {0x00DF, 0x1E9E},
+ {0x00E5, 0x212B},
+ {0x0130, 0x0130},
+ {0x0131, 0x0131},
+ {0x017F, 0x0053},
+ {0x01C4, 0x01C5},
+ {0x01C5, 0x01C6},
+ {0x01C6, 0x01C4},
+ {0x01C7, 0x01C8},
+ {0x01C8, 0x01C9},
+ {0x01C9, 0x01C7},
+ {0x01CA, 0x01CB},
+ {0x01CB, 0x01CC},
+ {0x01CC, 0x01CA},
+ {0x01F1, 0x01F2},
+ {0x01F2, 0x01F3},
+ {0x01F3, 0x01F1},
+ {0x0345, 0x0399},
+ {0x0392, 0x03B2},
+ {0x0395, 0x03B5},
+ {0x0398, 0x03B8},
+ {0x0399, 0x03B9},
+ {0x039A, 0x03BA},
+ {0x039C, 0x03BC},
+ {0x03A0, 0x03C0},
+ {0x03A1, 0x03C1},
+ {0x03A3, 0x03C2},
+ {0x03A6, 0x03C6},
+ {0x03A9, 0x03C9},
+ {0x03B2, 0x03D0},
+ {0x03B5, 0x03F5},
+ {0x03B8, 0x03D1},
+ {0x03B9, 0x1FBE},
+ {0x03BA, 0x03F0},
+ {0x03BC, 0x00B5},
+ {0x03C0, 0x03D6},
+ {0x03C1, 0x03F1},
+ {0x03C2, 0x03C3},
+ {0x03C3, 0x03A3},
+ {0x03C6, 0x03D5},
+ {0x03C9, 0x2126},
+ {0x03D0, 0x0392},
+ {0x03D1, 0x03F4},
+ {0x03D5, 0x03A6},
+ {0x03D6, 0x03A0},
+ {0x03F0, 0x039A},
+ {0x03F1, 0x03A1},
+ {0x03F4, 0x0398},
+ {0x03F5, 0x0395},
+ {0x1E60, 0x1E61},
+ {0x1E61, 0x1E9B},
+ {0x1E9B, 0x1E60},
+ {0x1E9E, 0x00DF},
+ {0x1FBE, 0x0345},
+ {0x2126, 0x03A9},
+ {0x212A, 0x004B},
+ {0x212B, 0x00C5},
+ {0x2160, 0x2170},
+ {0x2161, 0x2171},
+ {0x2162, 0x2172},
+ {0x2163, 0x2173},
+ {0x2164, 0x2174},
+ {0x2165, 0x2175},
+ {0x2166, 0x2176},
+ {0x2167, 0x2177},
+ {0x2168, 0x2178},
+ {0x2169, 0x2179},
+ {0x216A, 0x217A},
+ {0x216B, 0x217B},
+ {0x216C, 0x217C},
+ {0x216D, 0x217D},
+ {0x216E, 0x217E},
+ {0x216F, 0x217F},
+ {0x2170, 0x2160},
+ {0x2171, 0x2161},
+ {0x2172, 0x2162},
+ {0x2173, 0x2163},
+ {0x2174, 0x2164},
+ {0x2175, 0x2165},
+ {0x2176, 0x2166},
+ {0x2177, 0x2167},
+ {0x2178, 0x2168},
+ {0x2179, 0x2169},
+ {0x217A, 0x216A},
+ {0x217B, 0x216B},
+ {0x217C, 0x216C},
+ {0x217D, 0x216D},
+ {0x217E, 0x216E},
+ {0x217F, 0x216F},
+ {0x24B6, 0x24D0},
+ {0x24B7, 0x24D1},
+ {0x24B8, 0x24D2},
+ {0x24B9, 0x24D3},
+ {0x24BA, 0x24D4},
+ {0x24BB, 0x24D5},
+ {0x24BC, 0x24D6},
+ {0x24BD, 0x24D7},
+ {0x24BE, 0x24D8},
+ {0x24BF, 0x24D9},
+ {0x24C0, 0x24DA},
+ {0x24C1, 0x24DB},
+ {0x24C2, 0x24DC},
+ {0x24C3, 0x24DD},
+ {0x24C4, 0x24DE},
+ {0x24C5, 0x24DF},
+ {0x24C6, 0x24E0},
+ {0x24C7, 0x24E1},
+ {0x24C8, 0x24E2},
+ {0x24C9, 0x24E3},
+ {0x24CA, 0x24E4},
+ {0x24CB, 0x24E5},
+ {0x24CC, 0x24E6},
+ {0x24CD, 0x24E7},
+ {0x24CE, 0x24E8},
+ {0x24CF, 0x24E9},
+ {0x24D0, 0x24B6},
+ {0x24D1, 0x24B7},
+ {0x24D2, 0x24B8},
+ {0x24D3, 0x24B9},
+ {0x24D4, 0x24BA},
+ {0x24D5, 0x24BB},
+ {0x24D6, 0x24BC},
+ {0x24D7, 0x24BD},
+ {0x24D8, 0x24BE},
+ {0x24D9, 0x24BF},
+ {0x24DA, 0x24C0},
+ {0x24DB, 0x24C1},
+ {0x24DC, 0x24C2},
+ {0x24DD, 0x24C3},
+ {0x24DE, 0x24C4},
+ {0x24DF, 0x24C5},
+ {0x24E0, 0x24C6},
+ {0x24E1, 0x24C7},
+ {0x24E2, 0x24C8},
+ {0x24E3, 0x24C9},
+ {0x24E4, 0x24CA},
+ {0x24E5, 0x24CB},
+ {0x24E6, 0x24CC},
+ {0x24E7, 0x24CD},
+ {0x24E8, 0x24CE},
+ {0x24E9, 0x24CF},
+}
+
+// FoldCategory maps a category name to a table of
+// code points outside the category that are equivalent under
+// simple case folding to code points inside the category.
+// If there is no entry for a category name, there are no such points.
+var FoldCategory = map[string]*RangeTable{
+ "Ll": foldLl,
+ "Inherited": foldInherited,
+ "M": foldM,
+ "L": foldL,
+ "Mn": foldMn,
+ "Common": foldCommon,
+ "Greek": foldGreek,
+ "Lu": foldLu,
+ "Lt": foldLt,
+}
+
+var foldLl = &RangeTable{
+ R16: []Range16{
+ {0x0041, 0x005a, 1},
+ {0x00c0, 0x00d6, 1},
+ {0x00d8, 0x00de, 1},
+ {0x0100, 0x012e, 2},
+ {0x0132, 0x0136, 2},
+ {0x0139, 0x0147, 2},
+ {0x014a, 0x0178, 2},
+ {0x0179, 0x017d, 2},
+ {0x0181, 0x0182, 1},
+ {0x0184, 0x0186, 2},
+ {0x0187, 0x0189, 2},
+ {0x018a, 0x018b, 1},
+ {0x018e, 0x0191, 1},
+ {0x0193, 0x0194, 1},
+ {0x0196, 0x0198, 1},
+ {0x019c, 0x019d, 1},
+ {0x019f, 0x01a0, 1},
+ {0x01a2, 0x01a6, 2},
+ {0x01a7, 0x01a9, 2},
+ {0x01ac, 0x01ae, 2},
+ {0x01af, 0x01b1, 2},
+ {0x01b2, 0x01b3, 1},
+ {0x01b5, 0x01b7, 2},
+ {0x01b8, 0x01bc, 4},
+ {0x01c4, 0x01c5, 1},
+ {0x01c7, 0x01c8, 1},
+ {0x01ca, 0x01cb, 1},
+ {0x01cd, 0x01db, 2},
+ {0x01de, 0x01ee, 2},
+ {0x01f1, 0x01f2, 1},
+ {0x01f4, 0x01f6, 2},
+ {0x01f7, 0x01f8, 1},
+ {0x01fa, 0x0232, 2},
+ {0x023a, 0x023b, 1},
+ {0x023d, 0x023e, 1},
+ {0x0241, 0x0243, 2},
+ {0x0244, 0x0246, 1},
+ {0x0248, 0x024e, 2},
+ {0x0345, 0x0370, 43},
+ {0x0372, 0x0376, 4},
+ {0x0386, 0x0388, 2},
+ {0x0389, 0x038a, 1},
+ {0x038c, 0x038e, 2},
+ {0x038f, 0x0391, 2},
+ {0x0392, 0x03a1, 1},
+ {0x03a3, 0x03ab, 1},
+ {0x03cf, 0x03d8, 9},
+ {0x03da, 0x03ee, 2},
+ {0x03f4, 0x03f7, 3},
+ {0x03f9, 0x03fa, 1},
+ {0x03fd, 0x042f, 1},
+ {0x0460, 0x0480, 2},
+ {0x048a, 0x04c0, 2},
+ {0x04c1, 0x04cd, 2},
+ {0x04d0, 0x0526, 2},
+ {0x0531, 0x0556, 1},
+ {0x10a0, 0x10c5, 1},
+ {0x1e00, 0x1e94, 2},
+ {0x1e9e, 0x1efe, 2},
+ {0x1f08, 0x1f0f, 1},
+ {0x1f18, 0x1f1d, 1},
+ {0x1f28, 0x1f2f, 1},
+ {0x1f38, 0x1f3f, 1},
+ {0x1f48, 0x1f4d, 1},
+ {0x1f59, 0x1f5f, 2},
+ {0x1f68, 0x1f6f, 1},
+ {0x1f88, 0x1f8f, 1},
+ {0x1f98, 0x1f9f, 1},
+ {0x1fa8, 0x1faf, 1},
+ {0x1fb8, 0x1fbc, 1},
+ {0x1fc8, 0x1fcc, 1},
+ {0x1fd8, 0x1fdb, 1},
+ {0x1fe8, 0x1fec, 1},
+ {0x1ff8, 0x1ffc, 1},
+ {0x2126, 0x212a, 4},
+ {0x212b, 0x2132, 7},
+ {0x2183, 0x2c00, 2685},
+ {0x2c01, 0x2c2e, 1},
+ {0x2c60, 0x2c62, 2},
+ {0x2c63, 0x2c64, 1},
+ {0x2c67, 0x2c6d, 2},
+ {0x2c6e, 0x2c70, 1},
+ {0x2c72, 0x2c75, 3},
+ {0x2c7e, 0x2c80, 1},
+ {0x2c82, 0x2ce2, 2},
+ {0x2ceb, 0x2ced, 2},
+ {0xa640, 0xa66c, 2},
+ {0xa680, 0xa696, 2},
+ {0xa722, 0xa72e, 2},
+ {0xa732, 0xa76e, 2},
+ {0xa779, 0xa77d, 2},
+ {0xa77e, 0xa786, 2},
+ {0xa78b, 0xa78d, 2},
+ {0xa790, 0xa7a0, 16},
+ {0xa7a2, 0xa7a8, 2},
+ {0xff21, 0xff3a, 1},
+ },
+ R32: []Range32{
+ {0x10400, 0x10427, 1},
+ },
+}
+
+var foldInherited = &RangeTable{
+ R16: []Range16{
+ {0x0399, 0x03b9, 32},
+ {0x1fbe, 0x1fbe, 1},
+ },
+}
+
+var foldM = &RangeTable{
+ R16: []Range16{
+ {0x0399, 0x03b9, 32},
+ {0x1fbe, 0x1fbe, 1},
+ },
+}
+
+var foldL = &RangeTable{
+ R16: []Range16{
+ {0x0345, 0x0345, 1},
+ },
+}
+
+var foldMn = &RangeTable{
+ R16: []Range16{
+ {0x0399, 0x03b9, 32},
+ {0x1fbe, 0x1fbe, 1},
+ },
+}
+
+var foldCommon = &RangeTable{
+ R16: []Range16{
+ {0x039c, 0x03bc, 32},
+ },
+}
+
+var foldGreek = &RangeTable{
+ R16: []Range16{
+ {0x00b5, 0x0345, 656},
+ },
+}
+
+var foldLu = &RangeTable{
+ R16: []Range16{
+ {0x0061, 0x007a, 1},
+ {0x00b5, 0x00df, 42},
+ {0x00e0, 0x00f6, 1},
+ {0x00f8, 0x00ff, 1},
+ {0x0101, 0x012f, 2},
+ {0x0133, 0x0137, 2},
+ {0x013a, 0x0148, 2},
+ {0x014b, 0x0177, 2},
+ {0x017a, 0x017e, 2},
+ {0x017f, 0x0180, 1},
+ {0x0183, 0x0185, 2},
+ {0x0188, 0x018c, 4},
+ {0x0192, 0x0195, 3},
+ {0x0199, 0x019a, 1},
+ {0x019e, 0x01a1, 3},
+ {0x01a3, 0x01a5, 2},
+ {0x01a8, 0x01ad, 5},
+ {0x01b0, 0x01b4, 4},
+ {0x01b6, 0x01b9, 3},
+ {0x01bd, 0x01bf, 2},
+ {0x01c5, 0x01c6, 1},
+ {0x01c8, 0x01c9, 1},
+ {0x01cb, 0x01cc, 1},
+ {0x01ce, 0x01dc, 2},
+ {0x01dd, 0x01ef, 2},
+ {0x01f2, 0x01f3, 1},
+ {0x01f5, 0x01f9, 4},
+ {0x01fb, 0x021f, 2},
+ {0x0223, 0x0233, 2},
+ {0x023c, 0x023f, 3},
+ {0x0240, 0x0242, 2},
+ {0x0247, 0x024f, 2},
+ {0x0250, 0x0254, 1},
+ {0x0256, 0x0257, 1},
+ {0x0259, 0x025b, 2},
+ {0x0260, 0x0263, 3},
+ {0x0265, 0x0268, 3},
+ {0x0269, 0x026b, 2},
+ {0x026f, 0x0271, 2},
+ {0x0272, 0x0275, 3},
+ {0x027d, 0x0283, 3},
+ {0x0288, 0x028c, 1},
+ {0x0292, 0x0345, 179},
+ {0x0371, 0x0373, 2},
+ {0x0377, 0x037b, 4},
+ {0x037c, 0x037d, 1},
+ {0x03ac, 0x03af, 1},
+ {0x03b1, 0x03ce, 1},
+ {0x03d0, 0x03d1, 1},
+ {0x03d5, 0x03d7, 1},
+ {0x03d9, 0x03ef, 2},
+ {0x03f0, 0x03f2, 1},
+ {0x03f5, 0x03fb, 3},
+ {0x0430, 0x045f, 1},
+ {0x0461, 0x0481, 2},
+ {0x048b, 0x04bf, 2},
+ {0x04c2, 0x04ce, 2},
+ {0x04cf, 0x0527, 2},
+ {0x0561, 0x0586, 1},
+ {0x1d79, 0x1d7d, 4},
+ {0x1e01, 0x1e95, 2},
+ {0x1e9b, 0x1ea1, 6},
+ {0x1ea3, 0x1eff, 2},
+ {0x1f00, 0x1f07, 1},
+ {0x1f10, 0x1f15, 1},
+ {0x1f20, 0x1f27, 1},
+ {0x1f30, 0x1f37, 1},
+ {0x1f40, 0x1f45, 1},
+ {0x1f51, 0x1f57, 2},
+ {0x1f60, 0x1f67, 1},
+ {0x1f70, 0x1f7d, 1},
+ {0x1fb0, 0x1fb1, 1},
+ {0x1fbe, 0x1fd0, 18},
+ {0x1fd1, 0x1fe0, 15},
+ {0x1fe1, 0x1fe5, 4},
+ {0x214e, 0x2184, 54},
+ {0x2c30, 0x2c5e, 1},
+ {0x2c61, 0x2c65, 4},
+ {0x2c66, 0x2c6c, 2},
+ {0x2c73, 0x2c76, 3},
+ {0x2c81, 0x2ce3, 2},
+ {0x2cec, 0x2cee, 2},
+ {0x2d00, 0x2d25, 1},
+ {0xa641, 0xa66d, 2},
+ {0xa681, 0xa697, 2},
+ {0xa723, 0xa72f, 2},
+ {0xa733, 0xa76f, 2},
+ {0xa77a, 0xa77c, 2},
+ {0xa77f, 0xa787, 2},
+ {0xa78c, 0xa791, 5},
+ {0xa7a1, 0xa7a9, 2},
+ {0xff41, 0xff5a, 1},
+ },
+ R32: []Range32{
+ {0x10428, 0x1044f, 1},
+ },
+}
+
+var foldLt = &RangeTable{
+ R16: []Range16{
+ {0x01c4, 0x01c6, 2},
+ {0x01c7, 0x01c9, 2},
+ {0x01ca, 0x01cc, 2},
+ {0x01f1, 0x01f3, 2},
+ {0x1f80, 0x1f87, 1},
+ {0x1f90, 0x1f97, 1},
+ {0x1fa0, 0x1fa7, 1},
+ {0x1fb3, 0x1fc3, 16},
+ {0x1ff3, 0x1ff3, 1},
+ },
+}
+
+// FoldScript maps a script name to a table of
+// code points outside the script that are equivalent under
+// simple case folding to code points inside the script.
+// If there is no entry for a script name, there are no such points.
+var FoldScript = map[string]*RangeTable{}
+
+
+// Range entries: 3391 16-bit, 659 32-bit, 4050 total.
+// Range bytes: 20346 16-bit, 7908 32-bit, 28254 total.
+
+// Fold orbit bytes: 147 pairs, 588 bytes
diff --git a/src/pkg/websocket/client.go b/src/pkg/websocket/client.go
index e28382196..f066a1832 100644
--- a/src/pkg/websocket/client.go
+++ b/src/pkg/websocket/client.go
@@ -19,11 +19,13 @@ import (
)
type ProtocolError struct {
- os.ErrorString
+ ErrorString string
}
+func (err *ProtocolError) String() string { return string(err.ErrorString) }
+
var (
- ErrBadScheme = os.ErrorString("bad scheme")
+ ErrBadScheme = &ProtocolError{"bad scheme"}
ErrBadStatus = &ProtocolError{"bad status"}
ErrBadUpgrade = &ProtocolError{"missing or bad upgrade"}
ErrBadWebSocketOrigin = &ProtocolError{"missing or bad WebSocket-Origin"}
diff --git a/src/pkg/xml/read.go b/src/pkg/xml/read.go
index e2b349c3f..427c31158 100644
--- a/src/pkg/xml/read.go
+++ b/src/pkg/xml/read.go
@@ -106,6 +106,11 @@ import (
// The struct field may have type []byte or string.
// If there is no such field, the character data is discarded.
//
+// * If the XML element contains comments, they are accumulated in
+// the first struct field that has tag "comments". The struct
+// field may have type []byte or string. If there is no such
+// field, the comments are discarded.
+//
// * If the XML element contains a sub-element whose name matches
// the prefix of a struct field tag formatted as "a>b>c", unmarshal
// will descend into the XML structure looking for elements with the
@@ -120,17 +125,22 @@ import (
// maps the sub-element to that struct field.
//
// Unmarshal maps an XML element to a string or []byte by saving the
-// concatenation of that element's character data in the string or []byte.
+// concatenation of that element's character data in the string or
+// []byte.
+//
+// Unmarshal maps an attribute value to a string or []byte by saving
+// the value in the string or slice.
//
-// Unmarshal maps an XML element to a slice by extending the length
-// of the slice and mapping the element to the newly created value.
+// Unmarshal maps an XML element to a slice by extending the length of
+// the slice and mapping the element to the newly created value.
//
-// Unmarshal maps an XML element to a bool by setting it to the boolean
-// value represented by the string.
+// Unmarshal maps an XML element or attribute value to a bool by
+// setting it to the boolean value represented by the string.
//
-// Unmarshal maps an XML element to an integer or floating-point
-// field by setting the field to the result of interpreting the string
-// value in decimal. There is no check for overflow.
+// Unmarshal maps an XML element or attribute value to an integer or
+// floating-point field by setting the field to the result of
+// interpreting the string value in decimal. There is no check for
+// overflow.
//
// Unmarshal maps an XML element to an xml.Name by recording the
// element name.
@@ -241,7 +251,7 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
switch v := val; v.Kind() {
default:
- return os.ErrorString("unknown type " + v.Type().String())
+ return os.NewError("unknown type " + v.Type().String())
case reflect.Slice:
typ := v.Type()
@@ -323,9 +333,6 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
switch f.Tag {
case "attr":
strv := sv.FieldByIndex(f.Index)
- if strv.Kind() != reflect.String {
- return UnmarshalError(sv.Type().String() + " field " + f.Name + " has attr tag but is not type string")
- }
// Look for attribute.
val := ""
k := strings.ToLower(f.Name)
@@ -335,7 +342,7 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
break
}
}
- strv.SetString(val)
+ copyValue(strv, []byte(val))
case "comment":
if !saveComment.IsValid() {
@@ -454,33 +461,54 @@ Loop:
}
}
- var err os.Error
+ if err := copyValue(saveData, data); err != nil {
+ return err
+ }
+
+ switch t := saveComment; t.Kind() {
+ case reflect.String:
+ t.SetString(string(comment))
+ case reflect.Slice:
+ t.Set(reflect.ValueOf(comment))
+ }
+
+ switch t := saveXML; t.Kind() {
+ case reflect.String:
+ t.SetString(string(saveXMLData))
+ case reflect.Slice:
+ t.Set(reflect.ValueOf(saveXMLData))
+ }
+
+ return nil
+}
+
+func copyValue(dst reflect.Value, src []byte) (err os.Error) {
// Helper functions for integer and unsigned integer conversions
var itmp int64
getInt64 := func() bool {
- itmp, err = strconv.Atoi64(string(data))
+ itmp, err = strconv.Atoi64(string(src))
// TODO: should check sizes
return err == nil
}
var utmp uint64
getUint64 := func() bool {
- utmp, err = strconv.Atoui64(string(data))
+ utmp, err = strconv.Atoui64(string(src))
// TODO: check for overflow?
return err == nil
}
var ftmp float64
getFloat64 := func() bool {
- ftmp, err = strconv.Atof64(string(data))
+ ftmp, err = strconv.Atof64(string(src))
// TODO: check for overflow?
return err == nil
}
// Save accumulated data and comments
- switch t := saveData; t.Kind() {
+ switch t := dst; t.Kind() {
case reflect.Invalid:
// Probably a comment, handled below
default:
- return os.ErrorString("cannot happen: unknown type " + t.Type().String())
+ return os.NewError("cannot happen: unknown type " + t.Type().String())
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if !getInt64() {
return err
@@ -497,31 +525,16 @@ Loop:
}
t.SetFloat(ftmp)
case reflect.Bool:
- value, err := strconv.Atob(strings.TrimSpace(string(data)))
+ value, err := strconv.Atob(strings.TrimSpace(string(src)))
if err != nil {
return err
}
t.SetBool(value)
case reflect.String:
- t.SetString(string(data))
+ t.SetString(string(src))
case reflect.Slice:
- t.Set(reflect.ValueOf(data))
+ t.Set(reflect.ValueOf(src))
}
-
- switch t := saveComment; t.Kind() {
- case reflect.String:
- t.SetString(string(comment))
- case reflect.Slice:
- t.Set(reflect.ValueOf(comment))
- }
-
- switch t := saveXML; t.Kind() {
- case reflect.String:
- t.SetString(string(saveXMLData))
- case reflect.Slice:
- t.Set(reflect.ValueOf(saveXMLData))
- }
-
return nil
}
diff --git a/src/pkg/xml/read_test.go b/src/pkg/xml/read_test.go
index d4ae3700d..e07cb1531 100644
--- a/src/pkg/xml/read_test.go
+++ b/src/pkg/xml/read_test.go
@@ -325,3 +325,47 @@ func TestUnmarshalBadPaths(t *testing.T) {
}
}
}
+
+func TestUnmarshalAttrs(t *testing.T) {
+ var f AttrTest
+ if err := Unmarshal(StringReader(attrString), &f); err != nil {
+ t.Fatalf("Unmarshal: %s", err)
+ }
+ if !reflect.DeepEqual(f, attrStruct) {
+ t.Fatalf("have %#v\nwant %#v", f, attrStruct)
+ }
+}
+
+type AttrTest struct {
+ Test1 Test1
+ Test2 Test2
+}
+
+type Test1 struct {
+ Int int "attr"
+ Float float64 "attr"
+ Uint8 uint8 "attr"
+}
+
+type Test2 struct {
+ Bool bool "attr"
+}
+
+const attrString = `
+<?xml version="1.0" charset="utf-8"?>
+<attrtest>
+ <test1 int="8" float="23.5" uint8="255"/>
+ <test2 bool="true"/>
+</attrtest>
+`
+
+var attrStruct = AttrTest{
+ Test1: Test1{
+ Int: 8,
+ Float: 23.5,
+ Uint8: 255,
+ },
+ Test2: Test2{
+ Bool: true,
+ },
+}
diff --git a/src/pkg/xml/xml.go b/src/pkg/xml/xml.go
index 2cebbce75..e5d73dd02 100644
--- a/src/pkg/xml/xml.go
+++ b/src/pkg/xml/xml.go
@@ -659,17 +659,22 @@ func (p *Parser) RawToken() (Token, os.Error) {
return nil, p.err
}
if b != '=' {
- p.err = p.syntaxError("attribute name without = in element")
- return nil, p.err
- }
- p.space()
- data := p.attrval()
- if data == nil {
- return nil, p.err
+ if p.Strict {
+ p.err = p.syntaxError("attribute name without = in element")
+ return nil, p.err
+ } else {
+ p.ungetc(b)
+ a.Value = a.Name.Local
+ }
+ } else {
+ p.space()
+ data := p.attrval()
+ if data == nil {
+ return nil, p.err
+ }
+ a.Value = string(data)
}
- a.Value = string(data)
}
-
if empty {
p.needClose = true
p.toClose = name
diff --git a/src/pkg/xml/xml_test.go b/src/pkg/xml/xml_test.go
index 4e51cd53a..aba21a2b4 100644
--- a/src/pkg/xml/xml_test.go
+++ b/src/pkg/xml/xml_test.go
@@ -445,6 +445,33 @@ func TestUnquotedAttrs(t *testing.T) {
}
}
+func TestValuelessAttrs(t *testing.T) {
+ tests := [][3]string{
+ {"<p nowrap>", "p", "nowrap"},
+ {"<p nowrap >", "p", "nowrap"},
+ {"<input checked/>", "input", "checked"},
+ {"<input checked />", "input", "checked"},
+ }
+ for _, test := range tests {
+ p := NewParser(StringReader(test[0]))
+ p.Strict = false
+ token, err := p.Token()
+ if _, ok := err.(*SyntaxError); ok {
+ t.Errorf("Unexpected error: %v", err)
+ }
+ if token.(StartElement).Name.Local != test[1] {
+ t.Errorf("Unexpected tag name: %v", token.(StartElement).Name.Local)
+ }
+ attr := token.(StartElement).Attr[0]
+ if attr.Value != test[2] {
+ t.Errorf("Unexpected attribute value: %v", attr.Value)
+ }
+ if attr.Name.Local != test[2] {
+ t.Errorf("Unexpected attribute name: %v", attr.Name.Local)
+ }
+ }
+}
+
func TestCopyTokenCharData(t *testing.T) {
data := []byte("same data")
var tok1 Token = CharData(data)